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;
}
本文介绍了一种用于计算大整数开根号整数部分的高效算法,包括二分查找和高精度数学运算,适用于位数不超过1000位的大整数。

被折叠的 条评论
为什么被折叠?



