高精度开平方
时间限制: 1 Sec 内存限制: 128 MB题目描述
输入
一个整数 N。
输出
N 的平方根下取整。
样例输入
(如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
123456789012345678901234567890
样例输出
351364182882014
提示
对于 100%的数据,0<N<=10^1000。
别告诉我你想枚举,这种单调性问题肯定是二分答案啊,但是要用到高精度就很呵呵了,其实思想很简单,就是道堆代码的题罢了。不多说,先上代码吧
#include<cstdio>
#include<cstring>
#define max(a,b) a>b?a:b
struct node
{
int s[10000];
int len;
node(){memset(s,0,sizeof(s));len=0;}//结构体默认构造函数
void scan()//结构体成员函数,输入
{
char c[10000];
scanf("%s",c);
int o=strlen(c);
for(len=0;len<o;len++) s[len]=c[o-len-1]-'0';
}
bool operator < (node p) const//重载运算符
{
if(len!=p.len) return len<p.len;
for(int i=len-1;i>=0;i--)
if(s[i]!=p.s[i]) return s[i]<p.s[i];
return 0;
}
bool operator == (node p) const
{
for(int i=max(len,p.len)-1;i>=0;i--)
if(s[i]!=p.s[i]) return 0;
return 1;
}
bool operator > (node p) const
{
if(len!=p.len) return len>p.len;
for(int i=len-1;i>=0;i--)
if(s[i]!=p.s[i]) return s[i]>p.s[i];
return 0;
}
node operator + (node a)
{
node c;
c.len=max(len,a.len);
for(int i=0;i<c.len;i++)
{
c.s[i]+=s[i]+a.s[i];
if(c.s[i]>9) c.s[i]-=10,c.s[i+1]++;
}
if(c.s[c.len]) c.len++;
return c;
}
node operator / (int a)
{
int x=0;
node c;
c.len=len;
for(int i=len-1;i>=0;i--)
{
c.s[i]=(s[i]+x*10)/a;
x=s[i]%a;
}
if(!c.s[len-1]) c.len--;
return c;
}
node operator * (node a)
{
node c;
for(int i=0;i<len;i++)
for(int j=0;j<a.len;j++)
{
c.s[i+j]+=s[i]*a.s[j];
if(c.s[i+j]>9) c.s[i+j+1]+=c.s[i+j]/10,c.s[i+j]%=10;
}
c.len=len+a.len;
if(!c.s[c.len-1]) c.len--;
return c;
}
node operator + (int a)
{
s[0]+=a;
int i=0;
while(s[i]>9) s[i]-=10,s[i+1]++,i++;
if(s[len]) len++;
return *this;
}
node operator - (int a)
{
s[0]-=a;
int i=0;
while(s[i]<0) s[i]+=10,s[i+1]--,i++;
if(!s[len-1]) len--;
return *this;
}
};
int main()
{
node n,l,r,m,f;
n.scan();
l.s[0]=0,l.len=1;
r=n;
while(l<r)//二分答案
{
m=(l+r+1)/2;
f=m*m;
if(f==n) {l=m;break;}
else if(f>n) r=m-1;
else l=m;
}
for(int i=l.len-1;i>=0;i--)
printf("%d",l.s[i]);
}
好,答案是对了,但是。。。光荣的TLE了,超时无奈啊。。。log一个一千位的数。。。显然,二分我们并不能修改,但是我们可以 修改高精度运算的方式----压位处理 。
首先,我们数组的每个空间只存了一个一位数,浪费了这大好空间,循环也要超时,so,我们可以让数组的每个空间存一个多位数,这样做的话整个数组的长度就会大大减小,循环也会变快,但是压位处理要小心,不要遗留细节之处。先给一个存4位的代码吧。(只发修改了的地方)
struct node
{
int s[10000];
int len;
node(){memset(s,0,sizeof(s));len=0;}
void scan()//输入要修改
{
char c[10000];
scanf("%s",c);
int o=strlen(c);
for(;(len+1)*4<=o;len++)
{
for(int i=4;i>=1;i--)
s[len]=s[len]*10+c[o-len*4-i]-'0';
}
if(o%4!=0)
{
for(int i=0;i<o%4;i++)
s[len]=s[len]*10+c[i]-'0';
len++;
}
//for(int i=len-1;i>=0;i--) printf("%04d",s[i]);
//printf("\n");
}
node operator + (node a)
{
node c;
c.len=max(len,a.len);
for(int i=0;i<c.len;i++)
{
c.s[i]+=s[i]+a.s[i];
if(c.s[i]>9999) c.s[i]-=10000,c.s[i+1]++;//9和10要变成9999和10000
}
if(c.s[c.len]) c.len++;
return c;
}
node operator / (int a)
{
int x=0;
node c;
c.len=len;
for(int i=len-1;i>=0;i--)
{
c.s[i]=(s[i]+x*10000)/a;
x=s[i]%a;
}
if(!c.s[len-1]) c.len--;
return c;
}
node operator * (node a)
{
node c;
for(int i=0;i<len;i++)
for(int j=0;j<a.len;j++)
{
c.s[i+j]+=s[i]*a.s[j];
if(c.s[i+j]>9999) c.s[i+j+1]+=c.s[i+j]/10000,c.s[i+j]%=10000;
}
c.len=len+a.len;
if(!c.s[c.len-1]) c.len--;
return c;
}
node operator + (int a)
{
s[0]+=a;
int i=0;
while(s[i]>9999) s[i]-=10000,s[i+1]++,i++;
if(s[len]) len++;
return *this;
}
node operator - (int a)
{
s[0]-=a;
int i=0;
while(s[i]<0) s[i]+=10000,s[i+1]--,i++;
if(!s[len-1]) len--;
return *this;
}
};
int main()
{
printf("%d",l.s[l.len-1]);
for(int i=l.len-2;i>=0;i--)
printf("%04d",l.s[i]);//%04d,例如2会输出0002,12会输出0012
}
显然,这样就快多了,但是。。。1042ms.........看来我们还需要继续压位。
当压位到5位及其以上时,用乘法的中间过程可能溢出,所以需要用long long。
struct node
{
long long s[1005];
int len;
node(){memset(s,0,sizeof(s));len=0;}
void scan()
{
char c[1010];
scanf("%s",c);
int o=strlen(c);
for(;(len+1)*5<=o;len++)
{
for(int i=5;i>=1;i--)
s[len]=s[len]*10+c[o-len*5-i]-'0';
}
if(o%5!=0)
{
for(int i=0;i<o%5;i++)
s[len]=s[len]*10+c[i]-'0';
len++;
}
//for(int i=len-1;i>=0;i--) printf("%04d",s[i]);
//printf("\n");
}
node operator + (node a)
{
node c;
c.len=max(len,a.len);
for(int i=0;i<c.len;i++)
{
c.s[i]+=s[i]+a.s[i];
if(c.s[i]>99999) c.s[i]-=100000,c.s[i+1]++;
}
if(c.s[c.len]) c.len++;
return c;
}
node operator / (int a)
{
int x=0;
node c;
c.len=len;
for(int i=len-1;i>=0;i--)
{
c.s[i]=(s[i]+x*100000)/a;
x=s[i]%a;
}
if(!c.s[len-1]) c.len--;
return c;
}
node operator * (node a)
{
node c;
for(int i=0;i<len;i++)
for(int j=0;j<a.len;j++)
{
c.s[i+j]+=s[i]*a.s[j];
if(c.s[i+j]>99999) c.s[i+j+1]+=c.s[i+j]/100000,c.s[i+j]%=100000;
}
c.len=len+a.len;
if(!c.s[c.len-1]) c.len--;
return c;
}
node operator + (int a)
{
s[0]+=a;
int i=0;
while(s[i]>99999) s[i]-=100000,s[i+1]++,i++;
if(s[len]) len++;
return *this;
}
node operator - (int a)
{
s[0]-=a;
int i=0;
while(s[i]<0) s[i]+=100000,s[i+1]--,i++;
if(!s[len-1]) len--;
return *this;
}
};
int main()
{
printf("%lld",l.s[l.len-1]);
for(int i=l.len-2;i>=0;i--)
printf("%05lld",l.s[i]);
}
这就是压了5位,哦,终于AC了。爽。当然,用了long long应该能压更多位,大家自己去试吧。