bzoj 1876 //1876: [SDOI2009]SuperGCD //在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1876
更多题解,详见https://blog.csdn.net/mrcrack/article/details/90228694BZOJ刷题记录
//1876: [SDOI2009]SuperGCD
//在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1876
//先回顾CGD算法
//尝试写了非高精度的GCD,测试了样例,没有问题,代码如下
#include
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int main(){
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",gcd(a,b));
return 0;
}
//a%b可以用减法来处理,当a>b就让a=a-b,若a==0,则最大公约数找到,若0 //int 数组读入数据,逆序排列,即 数组角标小的 存储数据的低位
//测试了高精度数据的读入与输出。成功后继续代码的编写。
//高精度减法+高精度比大小
//样例通过,提交Time_Limit_Exceed。2019-6-11
//此文https://www.luogu.org/problemnew/solution/P2152?page=5思路不错,摘抄如下
辗转相减求a,b的gcd其实可以优化的:
1、若a为偶数,b为奇数:gcd(a,b)=gcd(a/2,b)
2、若a为奇数,b为偶数:gcd(a,b)=gcd(a,b/2)
3、若a,b都是偶数:gcd(a,b)=2*gcd(a/2,b/2)
3、若a,b都是奇数:gcd(a,b)=gcd(a-b,b) (a>b)
然后就涉及到高精度乘单精度,高精度减高精度,高精度除单精度……
//上述除了第3点,其它都没想到,有了思路,马上编码.
//针对2编写乘与除.
//样例通过,提交Wrong_Answer。2019-6-12
//一直怀疑时*2过程中的问题,测试了
//1024 512
//512
//果然,是有问题的
//for(i=1;i<=x[0];i++)x[i]*=2;//此处写成 for(i=1;i<=x[0];i++)x[i]*=2,x[i+1]+=x[i]/10,x[i]%=10;应先乘,再处理进位。
//for(i=1;i<=x[0];i++)x[i+1]+=x[i]/10,x[i]%=10;//为了添加此举,也排查了好久程序。
//i=x[0];//漏了此句,查了好久,即忘记i的初始化了
//修改,提交Wrong_Answer。2019-6-12
//测试
//3 4
//1
//发现有问题
//排查过程中,发现是处理sub及gcd中,x,y先后顺序的问题。
//测试了(1-10,1-10)里的数据,没有问题,提交Time_Limit_Exceed
//https://www.luogu.org/recordnew/show/19793602提交AC,但上面bzoj提交是Time_Limit_Exceed
//以下代码为 洛谷AC 4647ms / 0.79MB ,bzoj Time_Limit_Exceed 2019-6-12 15:20
//看了一堆AC的代码,多是python或是Java的赖皮代码
//听从此文https://www.cnblogs.com/zbtrs/p/7397038.html意见,
//这道题一定要压位来处理,不然会tle,压位后的操作与没有压位差不多,只不过mod的数变了,以前是逢10进1,现在是逢n进1.
//在纸上理解了一遍,发现原来理解有误
//原以为10000位,采用10位压缩,需处理10000-10=9990其实不是
//其实处理10000/10=1000位
//最后定位为8位的压缩方案,主要是受制于2^31-1的位数,即int的位数限制
//样例通过,提交Runtime_Error
//仔细想想,也是10000/8=1250
// 而#define maxn 1010
//修改#define maxn 1260提交AC 840 kb 908 ms
//没有感到兴奋,这是努力应得的,编码完全独立。2019-6-12 20:11
//以下为AC代码。
#include
#include
#define maxn 1260
#define BASE 100000000
#define WIDTH 8
int a[maxn],b[maxn],cnt=0;//cnt统计*2中2的阶乘数目
char str[maxn*8];
void print(int *x){
int i;
printf("%d",x[x[0]]);
for(i=x[0]-1;i>=1;i--)printf("%08d",x[i]);
printf("\n");
}
void read(int *x){//123456789
int i,len,offset,t,begin;
scanf("%s",str);
len=strlen(str);
if(len%WIDTH==0)x[0]=len/WIDTH;
else x[0]=len/WIDTH+1;
offset=len%WIDTH;//偏移量
for(i=offset;i>=1;i--)x[1]*=10,x[1]+=str[offset-i]-'0';//x[1]=1
if(offset)begin=2;
else begin=1;
for(i=offset;i
}
int cmp(int *x,int *y){//比大小 x>y 返回1,x==y返回0,x
if(x[0]>y[0])return 1;
if(x[0]
for(i=x[0];i>=1;i--)
if(x[i]>y[i])return 1;
else if(x[i]
}
void sub(int *x,int *y){//高精度减法 默认x>y 这一步,程序会预处理
int i;
for(i=1;i<=y[0];i++)x[i]-=y[i];
for(i=1;i<=x[0];i++)
if(x[i]<0)x[i]+=BASE,x[i+1]-=1;
i=x[0];
while(x[i]==0)i--;//处理前导0
x[0]=i;//漏了此句。之前确实写了,在测试代码过程中,误删了,查了半天。
}
void div(int *x){// 除2
int i,a=0,shang,yu;
for(i=x[0];i>=1;i--)a*=BASE,a+=x[i],shang=a/2,yu=a%2,x[i]=shang,a=yu;//shang商 yu余数
i=x[0];
while(x[i]==0)i--;//处理前导0
x[0]=i;
}
void mul(int *x){// 乘2
int i;
for(i=1;i<=x[0];i++)x[i]*=2;//此处写成 for(i=1;i<=x[0];i++)x[i]*=2,x[i+1]+=x[i]/10,x[i]%=10;应先乘,再处理进位。
for(i=1;i<=x[0];i++)x[i+1]+=x[i]/BASE,x[i]%=BASE;//为了添加此举,也排查了好久程序。
i=x[0];//漏了此句,查了好久,即忘记i的初始化了
while(x[i+1]>0)i++;
x[0]=i;
}
void gcd(int *x,int *y){//非高精度return b?gcd(b,a%b):a;
int i;
if(cmp(x,y)==0)return;
if(x[1]%2==0&&y[1]%2)div(x),gcd(x,y);//1、若a为偶数,b为奇数:gcd(a,b)=gcd(a/2,b)
else if(x[1]%2&&y[1]%2==0)div(y),gcd(x,y);//2、若a为奇数,b为偶数:gcd(a,b)=gcd(a,b/2)
else if(x[1]%2==0&&y[1]%2==0)cnt++,div(x),div(y),gcd(x,y);//3、若a,b都是偶数:gcd(a,b)=2*gcd(a/2,b/2)
else if(x[1]%2&&y[1]%2){//排查过程中,发现此花括号内容写得很乱。
if(cmp(x,y)>0)sub(x,y);
else sub(y,x);
gcd(x,y);
}
}
int main(){
int i;
memset(a,0,sizeof(a)),memset(b,0,sizeof(b));
read(a),read(b);
gcd(a,b);
for(i=1;i<=cnt;i++)mul(a);
print(a);
return 0;
}
//1876: [SDOI2009]SuperGCD
//在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1876
//先回顾CGD算法
//尝试写了非高精度的GCD,测试了样例,没有问题,代码如下
#include
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int main(){
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",gcd(a,b));
return 0;
}
//a%b可以用减法来处理,当a>b就让a=a-b,若a==0,则最大公约数找到,若0 //int 数组读入数据,逆序排列,即 数组角标小的 存储数据的低位
//测试了高精度数据的读入与输出。成功后继续代码的编写。
//高精度减法+高精度比大小
//样例通过,提交Time_Limit_Exceed。2019-6-11
//此文https://www.luogu.org/problemnew/solution/P2152?page=5思路不错,摘抄如下
辗转相减求a,b的gcd其实可以优化的:
1、若a为偶数,b为奇数:gcd(a,b)=gcd(a/2,b)
2、若a为奇数,b为偶数:gcd(a,b)=gcd(a,b/2)
3、若a,b都是偶数:gcd(a,b)=2*gcd(a/2,b/2)
3、若a,b都是奇数:gcd(a,b)=gcd(a-b,b) (a>b)
然后就涉及到高精度乘单精度,高精度减高精度,高精度除单精度……
//上述除了第3点,其它都没想到,有了思路,马上编码.
//针对2编写乘与除.
//样例通过,提交Wrong_Answer。2019-6-12
//一直怀疑时*2过程中的问题,测试了
//1024 512
//512
//果然,是有问题的
//for(i=1;i<=x[0];i++)x[i]*=2;//此处写成 for(i=1;i<=x[0];i++)x[i]*=2,x[i+1]+=x[i]/10,x[i]%=10;应先乘,再处理进位。
//for(i=1;i<=x[0];i++)x[i+1]+=x[i]/10,x[i]%=10;//为了添加此举,也排查了好久程序。
//i=x[0];//漏了此句,查了好久,即忘记i的初始化了
//修改,提交Wrong_Answer。2019-6-12
//测试
//3 4
//1
//发现有问题
//排查过程中,发现是处理sub及gcd中,x,y先后顺序的问题。
//测试了(1-10,1-10)里的数据,没有问题,提交Time_Limit_Exceed
//https://www.luogu.org/recordnew/show/19793602提交AC,但上面bzoj提交是Time_Limit_Exceed
//以下代码为 洛谷AC 4647ms / 0.79MB ,bzoj Time_Limit_Exceed 2019-6-12 15:20
#include
#include
#define maxn 10010
int a[maxn],b[maxn],c[maxn],cnt=0;//cnt统计*2中2的阶乘数目
char str[maxn];
void read(int *a){
int i,len;
scanf("%s",str+1);
len=strlen(str+1);
a[0]=len;
for(i=1;i<=len;i++)a[i]=str[len-i+1]-'0';
}
int cmp(int *x,int *y){//比大小 x>y 返回1,x==y返回0,x
if(x[0]>y[0])return 1;
if(x[0]
for(i=x[0];i>=1;i--)
if(x[i]>y[i])return 1;
else if(x[i]
}
void sub(int *x,int *y){//高精度减法 默认x>y 这一步,程序会预处理
int i;
for(i=1;i<=y[0];i++)x[i]-=y[i];
for(i=1;i<=x[0];i++)
if(x[i]<0)x[i]+=10,x[i+1]-=1;
i=x[0];
while(x[i]==0)i--;//处理前导0
x[0]=i;//漏了此句。之前确实写了,在测试代码过程中,误删了,查了半天。
}
void div(int *x){// 除2
int i,a=0,shang,yu;
for(i=x[0];i>=1;i--)a*=10,a+=x[i],shang=a/2,yu=a%2,x[i]=shang,a=yu;//shang商 yu余数
i=x[0];
while(x[i]==0)i--;//处理前导0
x[0]=i;
}
void mul(int *x){// 乘2
int i;
for(i=1;i<=x[0];i++)x[i]*=2;//此处写成 for(i=1;i<=x[0];i++)x[i]*=2,x[i+1]+=x[i]/10,x[i]%=10;应先乘,再处理进位。
for(i=1;i<=x[0];i++)x[i+1]+=x[i]/10,x[i]%=10;//为了添加此举,也排查了好久程序。
i=x[0];//漏了此句,查了好久,即忘记i的初始化了
while(x[i+1]>0)i++;
x[0]=i;
}
void gcd(int *x,int *y){//非高精度return b?gcd(b,a%b):a;
int i;
if(cmp(x,y)==0)return;
if(x[1]%2==0&&y[1]%2)div(x),gcd(x,y);//1、若a为偶数,b为奇数:gcd(a,b)=gcd(a/2,b)
else if(x[1]%2&&y[1]%2==0)div(y),gcd(x,y);//2、若a为奇数,b为偶数:gcd(a,b)=gcd(a,b/2)
else if(x[1]%2==0&&y[1]%2==0)cnt++,div(x),div(y),gcd(x,y);//3、若a,b都是偶数:gcd(a,b)=2*gcd(a/2,b/2)
else if(x[1]%2&&y[1]%2){//排查过程中,发现此花括号内容写得很乱。
if(cmp(x,y)>0)sub(x,y);
else sub(y,x);
gcd(x,y);
}
}
int main(){
int i;
memset(a,0,sizeof(a)),memset(b,0,sizeof(b));
read(a),read(b);
gcd(a,b);
for(i=1;i<=cnt;i++)mul(a);
for(i=a[0];i>=1;i--)printf("%d",a[i]);printf("\n");//查了半天,才发现代码写成 for(i=a[0];i>=1;i++)printf("%d",a[i]);printf("\n");
return 0;
}
//1876: [SDOI2009]SuperGCD
//在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1876
//先回顾CGD算法
//尝试写了非高精度的GCD,测试了样例,没有问题,代码如下
#include
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int main(){
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",gcd(a,b));
return 0;
}
//a%b可以用减法来处理,当a>b就让a=a-b,若a==0,则最大公约数找到,若0 //int 数组读入数据,逆序排列,即 数组角标小的 存储数据的低位
//测试了高精度数据的读入与输出。成功后继续代码的编写。
//高精度减法+高精度比大小
//样例通过,提交Time_Limit_Exceed。2019-6-11
//以下代码为洛谷中https://www.luogu.org/problemnew/show/P2152/64分代码,测试点7-10 TLE. bzoj中Time_Limit_Exceed
#include
#include
#define maxn 10010
int a[maxn],b[maxn],c[maxn];
char str[maxn];
void read(int *a){
int i,len;
scanf("%s",str+1);
len=strlen(str+1);
a[0]=len;
for(i=1;i<=len;i++)a[i]=str[len-i+1]-'0';
}
int cmp(int *x,int *y){//比大小 x>y 返回1,x==y返回0,x
if(x[0]>y[0])return 1;
if(x[0]
for(i=x[0];i>=1;i--)
if(x[i]>y[i])return 1;
else if(x[i]
}
void sub(int *x,int *y){//高精度减法 默认x>y 这一步,程序会预处理
int i;
for(i=1;i<=y[0];i++)x[i]-=y[i];
for(i=1;i<=x[0];i++)
if(x[i]<0)x[i]+=10,x[i+1]-=1;
i=x[0];
while(x[i]==0)i--;//处理前导0
x[0]=i;//漏了此句。之前确实写了,在测试代码过程中,误删了,查了半天。
}
void gcd(int *x,int *y){//非高精度return b?gcd(b,a%b):a;
int i;
if(cmp(x,y)==0)return;
while(cmp(x,y)>0)sub(x,y);
gcd(y,x);
}
int main(){
int i;
read(a),read(b);
if(cmp(a,b)>=0)gcd(a,b);
else gcd(b,a);
for(i=a[0];i>=1;i--)printf("%d",a[i]);printf("\n");//查了半天,才发现代码写成 for(i=a[0];i>=1;i++)printf("%d",a[i]);printf("\n");
return 0;
}