bzoj1876-更相减损术
题目描述
Sheng bill有着惊人的心算能力,甚至能用大脑计算出两个巨大的数的GCD(最大公约 数)!因此他经常和别人比
赛计算GCD。有一天Sheng bill很嚣张地找到了你,并要求和你比 赛,但是输给Sheng bill岂不是很丢脸!所以你
决定写一个程序来教训他。
输入
共两行: 第一行:一个数A。 第二行:一个数B。
0 < A , B ≤ 10 ^ 10000。
输出
一行,表示A和B的最大公约数。
样例输入
12
54
54
样例输出
6
这道题显然不能用欧几里得来做(高精度取模,乘,除)
根据数学Ⅲ,我们知道了更相损减术的做法
原文:可半者半之,不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。
操作:
- 任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
- 以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
优化:
在每次减好之后都对能除2的除2,若2个都能除2,同除2,gcd*2,(我也不知道为什么会快,但数据跑出来就是这样,(求教~~~))
//转自XT大佬
放一个基础代码
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int GX_gcd(int a,int b) { int tot,tt; if(b==0||a==0) return max(a,b); for(tot=0;a%2==0&&b%2==0;tot++,a/=2,b/=2); if(a%2==0) a/=2; else if(b%2==0) b/=2; if(a>b) tt=GX_gcd(a-b,b);else tt=GX_gcd(a,b-a); for(int i=1;i<=tot;i++) tt=tt*2; return tt; } int main() { int n,m; scanf("%d %d",&n,&m); cout<<GX_gcd(n,m)<<endl; }
这个不是高精度的
高精度且非递归见下
while(1) { if((a.nu[1]%2==0)&&(b.nu[1]%2==0)){a.div2();b.div2();num++;} else if((a.nu[1]%2==0)) a.div2(); else if((b.nu[1]%2==0)) b.div2(); if(a>b){a=a-b; if(a.z()){while(num--)b.mul2();b.out();break;}} else {b=b-a; if(b.z()){while(num--)a.mul2();a.out();break;}} }
这里采用了位压的手段,a.nu[x]表示a上的第x个块的数字
放一个hzw大神的代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define inf 1000000000 5 using namespace std; 6 char ch1[10005],ch2[10005]; 7 int la,lb,cnt; 8 struct data{int a[1205],l;}a,b; 9 bool com() 10 { 11 if(a.l<b.l)return 0; 12 if(a.l>b.l)return 1; 13 for(int i=a.l;i>0;--i) 14 if(a.a[i]>b.a[i])return 1; 15 else if(a.a[i]<b.a[i])return 0; 16 return 1; 17 } 18 void print(data a) 19 { 20 while(a.a[a.l]==0)a.l--; 21 for(int i=a.l;i>0;--i) 22 if(i==a.l)printf("%d",a.a[i]); 23 else printf("%09d",a.a[i]); 24 } 25 inline data sub(data a,data b) 26 { 27 int k; 28 data c; 29 for(int i=1;i<=1200;++i) 30 { 31 if(i<=b.l)c.a[i]=a.a[i]-b.a[i]; 32 else if(i<=a.l)c.a[i]=a.a[i]; 33 else c.a[i]=0; 34 if(c.a[i]<0) 35 { 36 c.a[i]+=inf; 37 a.a[i+1]--; 38 } 39 } 40 c.l=a.l; 41 while(c.a[c.l]==0&&c.l)c.l--; 42 return c; 43 } 44 void diva() 45 { 46 for(int i=1;i<=a.l;i++) 47 { 48 if(a.a[i]&1)a.a[i-1]+=inf/2; 49 a.a[i]>>=1; 50 } 51 if(!a.a[a.l])a.l--; 52 } 53 void divb() 54 { 55 for(int i=1;i<=b.l;i++) 56 { 57 if(b.a[i]&1)b.a[i-1]+=inf/2; 58 b.a[i]>>=1; 59 } 60 if(!b.a[b.l])b.l--; 61 } 62 void mul() 63 { 64 for(int i=a.l;i>0;i--) 65 { 66 a.a[i]<<=1; 67 a.a[i+1]+=a.a[i]/inf; 68 a.a[i]%=inf; 69 } 70 while(a.a[a.l]>0)a.l++; 71 for(int i=b.l;i>0;i--) 72 { 73 b.a[i]<<=1; 74 b.a[i+1]+=b.a[i]/inf; 75 b.a[i]%=inf; 76 } 77 while(b.a[b.l]>0)b.l++; 78 } 79 int main() 80 { 81 scanf("%s%s",ch1+1,ch2+1); 82 la=strlen(ch1+1);lb=strlen(ch2+1); 83 if(la%9)a.l=la/9+1; 84 else a.l=la/9; 85 if(lb%9)b.l=lb/9+1; 86 else b.l=lb/9; 87 for(int i=1;i<=a.l;++i) 88 { 89 int k1=max(1,la-i*9+1),k2=la-(i-1)*9; 90 for(int j=k1;j<=k2;++j) 91 a.a[i]=a.a[i]*10+ch1[j]-'0'; 92 } 93 for(int i=1;i<=b.l;++i) 94 { 95 int k1=max(1,lb-i*9+1),k2=lb-(i-1)*9; 96 for(int j=k1;j<=k2;++j) 97 b.a[i]=b.a[i]*10+ch2[j]-'0'; 98 } 99 while(1) 100 { 101 if((a.a[1]%2==0)&&(b.a[1]%2==0)){diva();divb();cnt++;} 102 else if((a.a[1]%2==0))diva(); 103 else if((b.a[1]%2==0))divb(); 104 if(com()){a=sub(a,b);if(!a.l){while(cnt--)mul();print(b);break;}} 105 else {b=sub(b,a);if(!b.l){while(cnt--)mul();print(a);break;}} 106 } 107 //system("pause"); 108 return 0; 109 }
其中对于压位后前导0的输出有很大的问题(压九位)
这里用了printf的神奇功能:printf("%09d",i);即可!
神奇的c++!