3119 高精度练习之大整数开根
题目描述 Description
给出一个正整数n,求n开根号后的整数部分的值。n的位数不超过1000位。
输入描述 Input Description
读入一个不超过1000位的正整数n。
输出描述 Output Description
输出所求答案
样例输入 Sample Input
17
样例输出 Sample Output
4
数据范围及提示 Data Size & Hint
容易想到的算法:二分,
题目描述 Description
给出一个正整数n,求n开根号后的整数部分的值。n的位数不超过1000位。
输入描述 Input Description
读入一个不超过1000位的正整数n。
输出描述 Output Description
输出所求答案
样例输入 Sample Input
17
样例输出 Sample Output
4
数据范围及提示 Data Size & Hint
n为不超过1000位的正整数 满足 1<=n <10^1000
算法分析:有手工迭代算法,
http://wenku.baidu.com/view/a80e1b81bceb19e8b8f6bada.html?re=view
例如394500,找到可能的左端点600,可能的右端点700,然后通过高精度大小判断,高精度*高精度,高精度除单精度得到答案。
#include<cstdio> #include<cstring> #include<algorithm> #define REP(I,start,end) for(int I=start;I<=end;I++) #define PER(I,start,end) for(int I=start;I>=end;I--) using namespace std; long long tmp[1100]; struct bigNumber{//????? int len; long long num[1100]; inline bool operator >(const bigNumber T)const{ if(len<T.len)return false; if(len>T.len)return true; PER(ii,len,1){ if(num[ii]<T.num[ii])return false; if(num[ii]>T.num[ii])return true; } return false; } inline bool operator ==(const bigNumber T)const{ if(len!=T.len)return false; PER(ii,len,1){ if(num[ii]!=T.num[ii])return false; } return true; } }a; inline bigNumber operator +(const bigNumber A,const bigNumber B){ bigNumber C; memset(C.num,0,sizeof(C.num)); C.len=max(A.len,B.len); REP(ii,1,C.len) C.num[ii]=A.num[ii]+B.num[ii]; REP(ii,1,C.len){ C.num[ii+1]+=C.num[ii]/10; C.num[ii]%=10; } while(C.num[C.len+1]){ C.len++; C.num[C.len+1]+=C.num[C.len]/10; C.num[C.len]%=10; } return C; } inline bigNumber operator *(const bigNumber A,const bigNumber B){ bigNumber C; memset(C.num,0,sizeof(C.num)); C.len=A.len+B.len-1; REP(ii,1,A.len) REP(jj,1,B.len) C.num[ii+jj-1]+=A.num[ii]*B.num[jj]; REP(ii,1,C.len){ C.num[ii+1]+=C.num[ii]/10; C.num[ii]%=10; } while(C.num[C.len+1]){ C.len++; C.num[C.len+1]+=C.num[C.len]/10; C.num[C.len]%=10; } return C; } inline bigNumber operator /(const bigNumber A,const long long B){//高精度/单精度 long long T=0ll; bigNumber C; memset(C.num,0ll,sizeof(C.num)); C.len=A.len; PER(ii,A.len,1){ T=(T*10+A.num[ii]); C.num[ii]=T/B; T=T%B; } while(C.len>1&&C.num[C.len]==0)C.len--; return C; } inline void print(const bigNumber T){ if(T.len==0){ printf("0"); return; } PER(ii,T.len,1) printf("%lld",T.num[ii]); printf("\n"); } inline void scan(bigNumber& T){ memset(T.num,0,sizeof(T.num)); T.len=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); if(ch=='0'){ ch=getchar(); if(ch<'0'||ch>'9') return; } while(ch=='0') ch=getchar(); while(ch>='0'&&ch<='9'){ T.num[++T.len]=ch-'0'; ch=getchar(); } if(T.len==1&&T.num[1]==0){ T.len=0; return; } REP(ii,1,T.len>>1) swap(T.num[ii],T.num[T.len-ii+1]); } int main() { int alen,al,ar,ahead; bigNumber left,right,mid,sqr; scan(a); if (a.len&1)ahead=a.num[a.len];//找出最高位数字,1-99 else ahead=a.num[a.len]*10+a.num[a.len-1]; for (int i=1;i<=9;i++){ //找出最高位对应的平方根 if(i*i<=ahead&&ahead<(i+1)*(i+1)) al=i; } memset(left.num,0,sizeof(left.num)); memset(right.num,0,sizeof(right.num)); left.len=right.len=(a.len-1)/2+1;//长度折半找到开根的左右端点。 left.num[left.len]=al; if (al<9) right.num[right.len]=al+1; else{ right.len++; right.num[right.len]=1; } while( true){ mid=left+right; mid=mid/2; if((mid==left)||(mid==right))break; sqr=mid*mid; if (sqr>a)//在左侧 right=mid; else left=mid; } print(mid); return 0; }