bzoj 1213 //1213: [HNOI2004]高精度开根 二分+高精度+结构体+运算符重载
bzoj 1213 //1213: [HNOI2004]高精度开根 //在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1213
//在线测评地址https://www.luogu.org/problem/P2293
更多题解,详见https://blog.csdn.net/mrcrack/article/details/90228694BZOJ刷题记录
高精度运算中,多用加减,少用乘除,若一定要用乘除,那就尽可能多用乘,少用除,否则出处处超时。2019-11-6 21:36
没有重载运算符的代码,编得凌乱,且得分不易。
//1213: [HNOI2004]高精度开根
//在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1213
//以高精度算法经验,预感此题会超越100行代码
//估计8位压位是少不了了。考虑相乘,数据可能会溢出,采用4位压位。
//估计需编写,比较大小的函数,高精度乘高精度,高精度除低精度,高精度加高精度。
//编写高精度算法,很重要的一条,每编写一个函数都要测试一遍。
//样例通过,bzoj里提交,
//Runtime_Error 1016 kb 16 ms C++/Edit 2384 B 2019-11-5
//在https://www.luogu.org/problem/P2293提交20分。20分代码如下,尽力了。
#include
#include
#define BASE 10000
#define BIT 4
#define maxn 10020
int a[maxn/BIT],b[maxn/BIT],c[maxn/BIT],m,left[maxn],right[maxn],mid[maxn],left1[maxn],one[10];
char s[maxn];
int cmp(int *x,int *y){//x>y 1;x
if(x[0]>y[0])return 1;
if(x[0]
if(x[i]>y[i])return 1;
else if(x[i]
}
void read(int *x){//读取,需要多编多练
int len,i,tmp;
char c;
scanf("%s",s+1);
len=strlen(s+1);
for(i=1;i<=len/2;i++)c=s[i],s[i]=s[len-i+1],s[len-i+1]=c;//逆序
x[0]=(len-1)/BIT+1;
for(i=1;i<=len;i++){//123456789
if((i-1)%BIT==0)x[(i-1)/BIT+1]=0,tmp=1;
x[(i-1)/BIT+1]+=(s[i]-'0')*tmp;
tmp*=10;
}
}
void print(int *x){
int i;
printf("%d",x[x[0]]);
for(i=x[0]-1;i>=1;i--)printf("%04d",x[i]);
}
void div(int *x,int *y){//y=x/2
int i;
x[x[0]+1]=0;
for(i=x[0];i>=1;i--)y[i]=(x[i+1]%2*BASE+x[i])/2;
i=x[0];
while(i&&!y[i])i--;//保证最后结果i>=1
y[0]=i;
}
void add(int *x,int *y,int *z){//z=x+y
int i;
z[0]=x[0]>y[0]?x[0]:y[0];
for(i=1;i<=z[0];i++){
z[i]+=x[i]+y[i];//此处错写成z[i]=x[i]+y[i];
z[i+1]=z[i]/BASE;//此处错写成z[i+1]+=z[i]/BASE;
z[i]%=BASE;//此处错写成z[i]/=BASE;
}
if(z[i])z[0]=i;
}
void mul(int *x,int *y,int *z){//z=x*y
int i,j;
z[0]=x[0]+y[0];
for(i=1;i<=x[0];i++)
for(j=1;j<=y[0];j++){
z[i+j-1]+=x[i]*y[j];
z[i+j-1+1]+=z[i+j-1]/BASE;//此处错写成z[i+j-1+1]=z[i+j-1]/BASE;
z[i+j-1]%=BASE;
}
i=z[0];
while(i&&!z[i])i--;
z[0]=i;
}
int judge(int *x){
int f[maxn/BIT],g[maxn/BIT],i;
memset(f,0,sizeof(f)),f[0]=1,f[1]=1;
for(i=1;i<=m;i++){
memset(g,0,sizeof(g));
mul(x,f,g);
memcpy(f,g,sizeof(g));
}
if(cmp(g,a)>=0)return 1;
else return 0;
}
int main(){
scanf("%d",&m);
read(a),left[0]=1,left[1]=0,memcpy(right,a,sizeof(a)),one[0]=1,one[1]=1;
while(cmp(left1,right)==-1){//left+1
add(left,right,b);
div(b,mid);
if(judge(mid))memcpy(right,mid,sizeof(mid));
else memcpy(left,mid,sizeof(mid));
memset(left1,0,sizeof(left1));
add(left,one,left1);
}
print(right);
}
AC代码如下
Accepted | 1072 kb | 21752 ms | C++/Edit | 3010 B |
//此文https://www.cnblogs.com/lxyyyy/p/10889765.html代码,与本人比较接近,进行对照研究,
//高精度算法,编写过程中种种的不便,决定还是要重载一些运算符
//样例通过,提交AC.2019-11-6 21:25
//看懂是一回事,编写又是另一回事,struct省去了许多初始化的麻烦
#include
#include
#define N 10100
#define BIT 4
#define BASE 10000
using namespace std;
int m;
struct num{
int a[N*2/BIT];//因涉及平方,故*2少不了
num(){
memset(a,0,sizeof(a));
}
void read(){
char s[N],c;
int len,i,tmp;
scanf("%s",s+1);
len=strlen(s+1);
for(i=1;i<=len/2;i++)c=s[i],s[i]=s[len-i+1],s[len-i+1]=c;//逆序
a[0]=(len-1)/BIT+1;
for(i=1;i<=len;i++){
if((i-1)%BIT==0)a[(i-1)/BIT+1]=0,tmp=1;
a[(i-1)/BIT+1]+=(s[i]-'0')*tmp,tmp*=10;
}
}
void print(){
int i;
printf("%d",a[a[0]]);
for(i=a[0]-1;i>=1;i--)printf("%0*d",BIT,a[i]);
}
}one,two,ten,l,r,mid,b;
num operator +(const num &p,const num &q){
num c;
int i;
c.a[0]=p.a[0]>q.a[0]?p.a[0]:q.a[0];
for(i=1;i<=c.a[0];i++)c.a[i]=p.a[i]+q.a[i];
for(i=1;i<=c.a[0];i++)c.a[i+1]+=c.a[i]/BASE,c.a[i]%=BASE;
if(c.a[c.a[0]+1])c.a[0]++;
return c;
}
num operator *(const num &p,const num &q){
num c;
int i,j;
c.a[0]=p.a[0]+q.a[0]-1;
for(i=1;i<=p.a[0];i++)
for(j=1;j<=q.a[0];j++)
c.a[i+j-1]+=p.a[i]*q.a[j];//此处错写成c.a[i+j-1]=p.a[i]*q.a[i];
for(i=1;i<=c.a[0];i++)c.a[i+1]+=c.a[i]/BASE,c.a[i]%=BASE;
if(c.a[c.a[0]+1])c.a[0]++;//此处错写成if(c.a[r.a[0]+1])c.a[0]++;
return c;//漏了此句
}
num operator /(const num &p,int q){
num c;
int y=0,i;
c.a[0]=p.a[0];
for(i=p.a[0];i>=1;i--){
y*=BASE,y+=p.a[i];
c.a[i]=y/q,y%=q;
}
while(c.a[0]&&!c.a[c.a[0]])c.a[0]--;//去除前导0
return c;
}
bool operator <(const num &p,const num &q){
int i;
if(p.a[0]!=q.a[0])return p.a[0]
if(p.a[i]!=q.a[i])return p.a[i]
}
bool operator ==(const num &p,const num &q){
int i;
if(p.a[0]!=q.a[0])return 0;
for(i=p.a[0];i>=1;i--)
if(p.a[i]!=q.a[i])return 0;
return 1;
}
num qpow(num p,int n){//快速幂
num c=one;
while(n){
if(n&1)c=c*p;
p=p*p,n>>=1;
}
return c;
}
int main(){
one.a[0]=1,one.a[1]=1,two.a[0]=1,two.a[1]=2,ten.a[0]=1,ten.a[1]=10;
scanf("%d",&m);
b.read();
if(m==1){
b.print();
return 0;
}
r=one;//漏了此句
while(qpow(r,m) b=b*qpow(ten,m),l=l*ten,r=r*ten;//因精度问题,将整体扩大10倍,之后,再将整体缩小为1/10,变回原来。//此处错写成b=b*ten,l=l*ten,r=r*ten;
while(l+one
if(qpow(mid,m) else r=mid;
}
if(qpow(r,m)==b)r=r/10,r.print();//此处错写成b=b/10,l=l/10,r=r/10;
else l=l/10,l.print();
return 0;
}