可能是我太弱...二分过不了...
这里讲一下另一个思路:
我们可以确定答案的位数,如果数N有奇数位,则答案位数为N/2+1,否则为N/2;
从位数L到1枚举每一位的数字;
枚举有个优化,设已枚举出的k-1位数为T(后接L-k+1个0),对于新枚举出的第k位数t,
设T'=T+t*10^(L-k),由于高精度乘法消耗太大,我们可以由T来推出T'^2;
T'^2=[T+t*10^(L-k)]^2=T^2+2Tt*10^(L-k)+t^2*10^2(L-k);
T^2可以在上次运算中得出,2Tt*10^(L-k)可以先计算出2Tt(高精度×单精度),再把答案扩大10^(L-k)倍;先计算出t^2(同样是高精度×单精度),再把答案扩大10^2(L-k)倍;
T'^2就求出来了,以此类推……
这里讲一下另一个思路:
我们可以确定答案的位数,如果数N有奇数位,则答案位数为N/2+1,否则为N/2;
从位数L到1枚举每一位的数字;
枚举有个优化,设已枚举出的k-1位数为T(后接L-k+1个0),对于新枚举出的第k位数t,
设T'=T+t*10^(L-k),由于高精度乘法消耗太大,我们可以由T来推出T'^2;
T'^2=[T+t*10^(L-k)]^2=T^2+2Tt*10^(L-k)+t^2*10^2(L-k);
T^2可以在上次运算中得出,2Tt*10^(L-k)可以先计算出2Tt(高精度×单精度),再把答案扩大10^(L-k)倍;先计算出t^2(同样是高精度×单精度),再把答案扩大10^2(L-k)倍;
T'^2就求出来了,以此类推……
这样就不存在高精度乘高精度导致TLE的问题了。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXL = 1005;
struct BI
{
short int num[MAXL];
int len;
void print()
{
for(int i = len; i >= 1; --i)
printf("%d", num[i]);
}
}big, ans, tmp;
BI operator + (BI A, BI B)
{
BI temp = {0};
int l = max(A.len, B.len);
for(int i = 1; i <= l; ++i)
{
temp.num[i] += A.num[i] + B.num[i];
temp.num[i + 1] += temp.num[i] / 10;
temp.num[i] %= 10;
}
if(temp.num[l + 1] > 0) temp.len = l + 1;
else temp.len = l;
return temp;
}
BI operator * (BI A, BI B)
{
BI temp[10] = {0}, re = {0};
temp[0].len = 1;
for(int i = 1; i <= 9; ++i)
temp[i] = A + temp[i - 1];
for(int i = 1; i <= B.len; ++i)
for(int j = 1; j <= temp[B.num[i]].len; ++j)
re.num[i + j - 1] += temp[B.num[i]].num[j];
for(int i = 1; i < A.len + B.len; ++i)
{
re.num[i + 1] += re.num[i] / 10;
re.num[i] %= 10;
}
if(re.num[A.len + B.len] > 0) re.len = A.len + B.len;
else re.len = A.len + B.len - 1;
return re;
}
BI operator - (BI A, BI B)
{
for(int i = 1; i <= B.len; ++i)
A.num[i] -= B.num[i];
for(int i = 1; i <= A.len; ++i)
{
while(A.num[i] < 0)
{
A.num[i] += 10;
A.num[i + 1] -= 1;
}
}
for(int i = A.len; i >= 1; --i)
if(A.num[i])
{
A.len = i;
break;
}
return A;
}
bool operator <= (const BI& A, const BI& B)
{
if(A.len < B.len) return true;
else if(A.len > B.len) return false;
for(int i = A.len; i >= 1; --i)
if(A.num[i] < B.num[i]) return true;
else if(A.num[i] > B.num[i]) return false;
return true;
}
bool flag = false;
void calc(BI ans, BI src)
{
BI op = {{0}, 1}, last = {{0}, 1}, op1 = {{0}, 1};
BI t2 = {{0, 2}, 1}, t1 = {{0, 1}, 1};
for(int i = ans.len; i >= 1; --i)
{
int j = 9;
for(; j >= ans.num[i]; --j)
{
BI t = {{0, j}, 1};
BI tmp = t2 * t * last;
if(i == 5 && j == 0)
j = 0;
//计算2ab
for(int k = tmp.len; k >= 1 && i > 1; --k)
{
tmp.num[k + i - 1] = tmp.num[k];
tmp.num[k] = 0;
}
if(tmp.num[i - 1 + tmp.len]) tmp.len = i - 1 + tmp.len;
//计算b^2
BI tmp2 = {{0, j}, 1};
tmp2 = tmp2 * tmp2;
for(int k = tmp2.len; k >= 1 && i > 1; --k)
{
tmp2.num[k + 2 * (i - 1)] = tmp2.num[k];
tmp2.num[k] = 0;
}
if(tmp2.num[2 * (i - 1) + tmp2.len]) tmp2.len = 2 * (i - 1) + tmp2.len;
op = op1 + tmp + tmp2;
if(op <= src) break;
}
ans.num[i] = j;
last = ans;
op1 = op;
}
ans.print();
}
int main()
{
char c;
while(scanf("%c", &c) != EOF)
{
tmp.num[++tmp.len] = c - '0';
}
big.len = tmp.len;
for(int i = 1; i <= tmp.len; ++i) big.num[i] = tmp.num[tmp.len - i + 1];
if(big.len & 1)
{
memset(ans.num, 0, sizeof(ans.num));
ans.len = (big.len >> 1) + 1;
ans.num[ans.len] = 1;
}
else
{
memset(ans.num, 0, sizeof(ans.num));
ans.len = big.len >> 1;
ans.num[ans.len] = 1;
}
calc(ans, big);
return 0;
}