叫Very simple problem的通常都不简单。。。
此题就是让你求一个数的平方根取整。但是这个数特别大10^1000。所以不能(int)sqrt。。
查了一下解题报告,有两种方法。
第一种是模拟徒手开方,第二种是高精度+二分。
这里先整理徒手开方的解法。
(1)把被开方数(如22146436)从右向左每隔两位用撇号分开(如22’14’64’36);
(2)从左边第一段(如22)求得算术平方根的第一位数字(如4) ;
(3)从第一段减去这第一位数字的平方(如22-42=6),再把被开方数的第二段写下来,作为第一个余数(如614);
(4)把所得的第一位数字(如4)乘以20,去除第一个余数所得的商的整数部分(如614÷(4×20)=7.675的整数部分7)作为试商(注:如果这个整数部分大于或者等于10,就改用9作试商,如果第一个余数小于第一位数字乘以20的积,则得试商0);
(5)把第一位数字的20倍加上试商的和,乘以这个试商所得值不大于第一个余数时(如(4×20+7)×7=609≤614),这个试商就是算术平方根的第二位数字(注:如果所得的积大于余数时,就要把试商减去1再试,直到积小于或者等于余数为止);
(6)用第一个余数减去第一位数字的20倍加上试商的和乘以该试商所得值的差(如614-609=5),往后用同样的方法,继续求算术平方根的其他各位数字。
把这种过程编程实现即可。
如果位数是奇数,则在最高位前加一个0,使其依然可以被两两分割。
省去试商的过程,从9开始枚举到0,找到t,使得目前的 (ans*20+t)*t 不大于当前余数。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
bool Check(char *rem,int s,int e,char *ans,int la,char *s3)
{
int ls3,ite,i,n;
char s1[2000],s2[2000];
strcpy(s1,rem);
strcpy(s2,ans);
s3[0]=ans[la-1];
n=s3[0]-'0';
ite=0;
ls3=1;
//乘以20
for (i=la-2; i>=0; i--)
{
ite+=(s2[i]-'0')*2;
s3[ls3]=ite%10+'0';
ite/=10;
ls3++;
}
if (ite != 0)
{
s3[ls3]=ite+'0';
ls3++;
}
while (s3[ls3-1] == '0' && ls3 > 1)
ls3--;
s3[ls3]='\0';
ite=0;
//加上n后,再乘以n
for (i=0; i<ls3; i++)
{
ite+=(s3[i]-'0')*n;
s3[i]=ite%10+'0';
ite/=10;
}
while (ite != 0)
{
s3[ls3]=ite%10+'0';
ite/=10;
ls3++;
}
while (s3[ls3-1] == '0' && ls3 > 1)
ls3--;
s3[ls3]='\0';
strrev(s3);
if (ls3 == 1)
{
s3[ls3]=s3[0];
s3[0]='0';
ls3++;
}
//判断大小
if (e-s < ls3)
{
return false;
}
else if (e-s > ls3)
{
return true;
}
else //位数相等的情况下
{
for (i=0; i<ls3; i++)
{
if (rem[s+i] < s3[i])
return false;
else if (rem[s+i] > s3[i])
return true;
}
return true;
}
}
void ChangeRem(char *rem,int *s,int e,char *s3)
{
int ls,i;
i=e-1;
ls=strlen(s3)-1;
while (ls >= 0)
{
if (rem[i] >= s3[ls])
{
rem[i]-=s3[ls];
rem[i]+='0';
}
else
{
rem[i-1]-=1;
rem[i]=(rem[i]-s3[ls])+10+'0';
}
ls--;
i--;
}
while (rem[(*s)] == '0')
{
(*s)++;
}
}
char *BigSqrt(char *str)
{
int i,j,ls,la,lr,sr;
char num[2000],ans[2000],rem[2000],tc,tstr[2000];
la=0;
lr=0;
sr=0;
ls=strlen(str);
if ((ls&1) == 1) //如果位数是奇数,则在最高位加0
{
num[0]='0';
strcpy(num+1,str);
ls++;
}
else
{
strcpy(num,str);
}
for (i=0; i<ls; i+=2)
{
rem[lr]=num[i];
rem[lr+1]=num[i+1];
lr+=2;
tc='9'+1;
while (tc--) //从9到0
{
ans[la]=tc;
ans[la+1]='\0';
if (Check(rem,sr,lr,ans,la+1,tstr) == true) //判断(ans*20+t)*t是否不大于当前余数
{
//满足,对当前余数remaider-(ans*20+t)*t
la++;
ChangeRem(rem,&sr,lr,tstr);
break; //找到了平方根的这一位上的数,直接跳出
}
}
}
return ans;
}
int main()
{
char str[2000];
scanf("%s",str);
printf("%s",BigSqrt(str));
}