More actions
imported>Unknown No edit summary |
(Table transclusion repair v1) |
||
| Line 5: | Line 5: | ||
|} | |} | ||
Closed Form 구하는데 약 3~4시간 걸린 것 같다. 계차수열을 이용해서 다음과 같은 Closed Form을 구했다. | Closed Form 구하는데 약 3~4시간 걸린 것 같다. 계차수열을 이용해서 다음과 같은 Closed Form을 구했다. | ||
T(n) = (n<sup>4</sup> - 6n<sup>3</sup> + 23n<sup>2</sup> - 18n + 24) / 24 | |||
이론상으론 O(1) 시간만에 되겠지만 문제는 입력범위가 2 | 이론상으론 O(1) 시간만에 되겠지만 문제는 입력범위가 2 <sup>31</sup> - 1 까지 들어올 수 있기 때문에 고정도 연산을 수행해야 한다. GNU C++ 이나 Java는 고정도 연산을 수행할 수 있는 클래스를 포함하고 있으나, 윈도우 C++에는 없다(혹, 내가 못찾는 것일수도 있다). 따라서 고정도 연산을 수행할 수 있는 클래스를 짰다. 성능이 너무 떨어진다. O(1) 을 O(n<sup>5</sup>) 정도로 바꿔 놓은 듯한 느낌이다. 이 Class를 개선한뒤 다시 테스트 해봐야 겠다. | ||
== 코드 == | == 코드 == | ||
=== BigInteger.h === | === BigInteger.h === | ||
| Line 33: | Line 33: | ||
{ | { | ||
public: | public: | ||
char digit | char digit[MAXDIGITS]; | ||
int signbit; | int signbit; | ||
int lastdigit; | int lastdigit; | ||
| Line 44: | Line 44: | ||
while (n / 10) | while (n / 10) | ||
{ | { | ||
digit | digit[lastdigit++] = n % 10; | ||
n /= 10; | n /= 10; | ||
} | } | ||
digit | digit[lastdigit] = n % 10; | ||
for (i = lastdigit + 1; i < MAXDIGITS; i++) | for (i = lastdigit + 1; i < MAXDIGITS; i++) | ||
digit | digit[i] = 0; | ||
} | } | ||
BigInteger() | BigInteger() | ||
| Line 55: | Line 55: | ||
int i; | int i; | ||
for (i = 0; i < MAXDIGITS; i++) | for (i = 0; i < MAXDIGITS; i++) | ||
digit | digit[i] = 0; | ||
signbit = PLUS; | signbit = PLUS; | ||
lastdigit = 0; | lastdigit = 0; | ||
| Line 63: | Line 63: | ||
if (signbit == MINUS) cout << "-"; | if (signbit == MINUS) cout << "-"; | ||
for (int i = lastdigit; i >= 0; i--) | for (int i = lastdigit; i >= 0; i--) | ||
cout << (int)digit | cout << (int)digit[i]; | ||
} | } | ||
void input() | void input() | ||
| Line 69: | Line 69: | ||
int startI = 0; | int startI = 0; | ||
int i, j; | int i, j; | ||
char temp | char temp[MAXDIGITS]; | ||
while (cin.peek() == ' ' || cin.peek() == '\n') | while (cin.peek() == ' ' || cin.peek() == '\n') | ||
| Line 77: | Line 77: | ||
lastdigit = strlen(temp) - 1; | lastdigit = strlen(temp) - 1; | ||
signbit = PLUS; | signbit = PLUS; | ||
if (temp | if (temp[0] == '-') | ||
{ | { | ||
signbit = MINUS; | signbit = MINUS; | ||
| Line 83: | Line 83: | ||
lastdigit--; | lastdigit--; | ||
} | } | ||
else if (temp | else if (temp[0] == '+') | ||
{ | { | ||
startI = 1; | startI = 1; | ||
| Line 90: | Line 90: | ||
j = 0; | j = 0; | ||
for (i = lastdigit + startI; i >= startI; i--) | for (i = lastdigit + startI; i >= startI; i--) | ||
digit | digit[j++] = temp[i] - '0'; | ||
} | } | ||
public: | public: | ||
friend void elminatePreZero(BigInteger& n) | friend void elminatePreZero(BigInteger& n) | ||
{ | { | ||
while (n.lastdigit > 0 && n.digit | while (n.lastdigit > 0 && n.digit[n.lastdigit] == 0) | ||
n.lastdigit--; | n.lastdigit--; | ||
if (n.lastdigit == 0 && n.digit | if (n.lastdigit == 0 && n.digit[0] == 0) | ||
n.signbit = PLUS; | n.signbit = PLUS; | ||
} | } | ||
| Line 109: | Line 109: | ||
for (i = a.lastdigit; i >= 0; i--) | for (i = a.lastdigit; i >= 0; i--) | ||
{ | { | ||
if (a.digit | if (a.digit[i] > b.digit[i]) | ||
return (MINUS * a.signbit); | return (MINUS * a.signbit); | ||
if (b.digit | if (b.digit[i] > a.digit[i]) | ||
return (PLUS * a.signbit); | return (PLUS * a.signbit); | ||
} | } | ||
| Line 119: | Line 119: | ||
{ | { | ||
int i; | int i; | ||
if (n.lastdigit == 0 && n.digit | if (n.lastdigit == 0 && n.digit[0] == 0) return; | ||
for (i = n.lastdigit; i >= 0; i--) | for (i = n.lastdigit; i >= 0; i--) | ||
n.digit | n.digit[i+d] = n.digit[i]; | ||
for (i = 0; i < d; i++) n.digit | for (i = 0; i < d; i++) n.digit[i] = 0; | ||
n.lastdigit = n.lastdigit + d; | n.lastdigit = n.lastdigit + d; | ||
} | } | ||
| Line 150: | Line 150: | ||
for (i = 0; i <= ret.lastdigit; i++) | for (i = 0; i <= ret.lastdigit; i++) | ||
{ | { | ||
ret.digit | ret.digit[i] = (carry + a.digit[i] + b.digit[i]) % 10; | ||
carry = (carry + a.digit | carry = (carry + a.digit[i] + b.digit[i]) / 10; | ||
} | } | ||
elminatePreZero(ret); | elminatePreZero(ret); | ||
| Line 180: | Line 180: | ||
for (i = 0; i <= ret.lastdigit; i++) | for (i = 0; i <= ret.lastdigit; i++) | ||
{ | { | ||
v = a.digit | v = a.digit[i] - borrow - b.digit[i]; | ||
if (a.digit | if (a.digit[i] > 0) | ||
borrow = 0; | borrow = 0; | ||
if (v < 0) | if (v < 0) | ||
| Line 188: | Line 188: | ||
borrow = 1; | borrow = 1; | ||
} | } | ||
ret.digit | ret.digit[i] = v % 10; | ||
} | } | ||
elminatePreZero(ret); | elminatePreZero(ret); | ||
| Line 201: | Line 201: | ||
for (i = 0; i <= b.lastdigit; i++) | for (i = 0; i <= b.lastdigit; i++) | ||
{ | { | ||
for (j = 1; j <= b.digit | for (j = 1; j <= b.digit[i]; j++) | ||
{ | { | ||
tmp = ret + row; | tmp = ret + row; | ||
| Line 228: | Line 228: | ||
{ | { | ||
shiftDigit(row, 1); | shiftDigit(row, 1); | ||
row.digit | row.digit[0] = a.digit[i]; | ||
ret.digit | ret.digit[i] = 0; | ||
while (compare(row, b) != PLUS) | while (compare(row, b) != PLUS) | ||
{ | { | ||
ret.digit | ret.digit[i]++; | ||
tmp = row - b; | tmp = row - b; | ||
row = tmp; | row = tmp; | ||
Latest revision as of 12:46, 27 March 2026
소감
| 2006-01-08 Accepted 4.244 444 |
Closed Form 구하는데 약 3~4시간 걸린 것 같다. 계차수열을 이용해서 다음과 같은 Closed Form을 구했다.
T(n) = (n4 - 6n3 + 23n2 - 18n + 24) / 24
이론상으론 O(1) 시간만에 되겠지만 문제는 입력범위가 2 31 - 1 까지 들어올 수 있기 때문에 고정도 연산을 수행해야 한다. GNU C++ 이나 Java는 고정도 연산을 수행할 수 있는 클래스를 포함하고 있으나, 윈도우 C++에는 없다(혹, 내가 못찾는 것일수도 있다). 따라서 고정도 연산을 수행할 수 있는 클래스를 짰다. 성능이 너무 떨어진다. O(1) 을 O(n5) 정도로 바꿔 놓은 듯한 느낌이다. 이 Class를 개선한뒤 다시 테스트 해봐야 겠다.
코드
BigInteger.h
//////////////////////////////////////////////////////////////////////////
// Big Integer Class - C++
// 만든이 : Moon, Bo-chang.
// 만든 날짜 : 2006 / 1 / 7
// 마지막으로 수정한 날짜 :
// 주의 : 오버플로우 처리 안함
// 지원하는 연산 : +(덧셈), -(뺄셈), *(곱셈), /(나눗셈) - 나눗셈 연산에서 나머지는 버린다.
// 함수 호출이 모두 복사로 이루어지므로 성능이 크게 떨어진다.
//////////////////////////////////////////////////////////////////////////
#pragma once
#include <iostream>
using namespace std;
#include <cstring>
#define MAXDIGITS 100
#define PLUS 1
#define MINUS -1
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
class BigInteger
{
public:
char digit[MAXDIGITS];
int signbit;
int lastdigit;
public:
BigInteger(int n)
{
int i;
lastdigit = 0;
signbit = (n < 0) ? MINUS : PLUS;
while (n / 10)
{
digit[lastdigit++] = n % 10;
n /= 10;
}
digit[lastdigit] = n % 10;
for (i = lastdigit + 1; i < MAXDIGITS; i++)
digit[i] = 0;
}
BigInteger()
{
int i;
for (i = 0; i < MAXDIGITS; i++)
digit[i] = 0;
signbit = PLUS;
lastdigit = 0;
}
void print()
{
if (signbit == MINUS) cout << "-";
for (int i = lastdigit; i >= 0; i--)
cout << (int)digit[i];
}
void input()
{
int startI = 0;
int i, j;
char temp[MAXDIGITS];
while (cin.peek() == ' ' || cin.peek() == '\n')
cin.get();
cin >> temp;
lastdigit = strlen(temp) - 1;
signbit = PLUS;
if (temp[0] == '-')
{
signbit = MINUS;
startI = 1;
lastdigit--;
}
else if (temp[0] == '+')
{
startI = 1;
lastdigit--;
}
j = 0;
for (i = lastdigit + startI; i >= startI; i--)
digit[j++] = temp[i] - '0';
}
public:
friend void elminatePreZero(BigInteger& n)
{
while (n.lastdigit > 0 && n.digit[n.lastdigit] == 0)
n.lastdigit--;
if (n.lastdigit == 0 && n.digit[0] == 0)
n.signbit = PLUS;
}
friend int compare(BigInteger& a, BigInteger& b)
{
int i;
if (a.signbit == MINUS && b.signbit == PLUS) return PLUS;
if (a.signbit == PLUS && b.signbit == MINUS) return MINUS;
if (b.lastdigit > a.lastdigit) return (PLUS * a.signbit);
if (a.lastdigit > b.lastdigit) return (MINUS * a.signbit);
for (i = a.lastdigit; i >= 0; i--)
{
if (a.digit[i] > b.digit[i])
return (MINUS * a.signbit);
if (b.digit[i] > a.digit[i])
return (PLUS * a.signbit);
}
return 0;
}
friend void shiftDigit(BigInteger& n, int d)
{
int i;
if (n.lastdigit == 0 && n.digit[0] == 0) return;
for (i = n.lastdigit; i >= 0; i--)
n.digit[i+d] = n.digit[i];
for (i = 0; i < d; i++) n.digit[i] = 0;
n.lastdigit = n.lastdigit + d;
}
friend BigInteger operator+(BigInteger a, BigInteger b)
{
int carry;
BigInteger ret;
int i;
if (a.signbit == MINUS && b.signbit == PLUS)
{
a.signbit = PLUS;
ret = b - a;
a.signbit = MINUS;
}
else if (a.signbit == PLUS && b.signbit == MINUS)
{
b.signbit = PLUS;
ret = a - b;
b.signbit = MINUS;
}
else
{
ret.signbit = a.signbit;
ret.lastdigit = MAX(a.lastdigit, b.lastdigit) + 1;
carry = 0;
for (i = 0; i <= ret.lastdigit; i++)
{
ret.digit[i] = (carry + a.digit[i] + b.digit[i]) % 10;
carry = (carry + a.digit[i] + b.digit[i]) / 10;
}
elminatePreZero(ret);
}
return ret;
}
friend BigInteger operator-(BigInteger a, BigInteger b)
{
BigInteger ret;
int borrow, v;
int i;
if (a.signbit == MINUS || b.signbit == MINUS)
{
b.signbit = -1 * b.signbit;
ret = a + b;
b.signbit = -1 * b.signbit;
return ret;
}
if (compare(a,b) == PLUS)
{
ret = b - a;
ret.signbit = MINUS;
return ret;
}
ret.lastdigit = MAX(a.lastdigit,b.lastdigit);
borrow = 0;
for (i = 0; i <= ret.lastdigit; i++)
{
v = a.digit[i] - borrow - b.digit[i];
if (a.digit[i] > 0)
borrow = 0;
if (v < 0)
{
v = v + 10;
borrow = 1;
}
ret.digit[i] = v % 10;
}
elminatePreZero(ret);
return ret;
}
friend BigInteger operator*(BigInteger a, BigInteger b)
{
BigInteger row, tmp, ret;
int i, j;
row = a;
for (i = 0; i <= b.lastdigit; i++)
{
for (j = 1; j <= b.digit[i]; j++)
{
tmp = ret + row;
ret = tmp;
}
shiftDigit(row, 1);
}
ret.signbit = a.signbit * b.signbit;
elminatePreZero(ret);
return ret;
}
friend BigInteger operator/(BigInteger a, BigInteger b)
{
BigInteger row, tmp, ret;
int asign, bsign;
int i;
ret.signbit = a.signbit * b.signbit;
asign = a.signbit;
bsign = b.signbit;
a.signbit = PLUS;
b.signbit = PLUS;
ret.lastdigit = a.lastdigit;
for (i = a.lastdigit; i >= 0; i--)
{
shiftDigit(row, 1);
row.digit[0] = a.digit[i];
ret.digit[i] = 0;
while (compare(row, b) != PLUS)
{
ret.digit[i]++;
tmp = row - b;
row = tmp;
}
}
elminatePreZero(ret);
a.signbit = asign;
b.signbit = bsign;
return ret;
}
};
main.cpp
#include "BigInteger.h"
int main()
{
int nCase;
BigInteger a(6), b(23), c(18), d(24);
BigInteger n, result;
cin >> nCase;
for (int i = 0; i < nCase; i++)
{
n.input();
result = (n * n * n * n - a * n * n * n + b * n * n - c * n + d) / d;
result.print();
cout << endl;
}
return 0;
}