最大公约数(信息学奥赛一本通 1627)
【题目描述】
给出两个正整数 A,B,求它们的最大公约数。
【输入】
输入共两行,第一行一个正整数 A,第二行一个正整数 B。
【输出】
在第一行输出一个整数,表示 A,B 的最大公约数。
【输入样例】
18
24
【输出样例】
6
【提示】
数据范围与提示:
对于 60% 的数据,1≤A,B≤1018;
对于 100% 的数据,1≤A,B≤103000 。
首先看到这道题的数据范围之后,我们肯定是得用高精度呐,然后为了方便一点,缩小数组大小,我们还可以引进“压位高精度”,一般来说,最好使用四位压一位,用五位的话容易爆掉...
--->关于“压位高精”,可以去看看这位大佬的博客,感jio讲的很清楚
进入正题,此题要求两个高精的“最大公约数”,那我们肯定会想到用“二进制算法”呐,
--->关于“二进制算法”,可以去看看我的另一篇博客(应该在最后面有讲到),也称“更相减损术”啦
那我直接上代码吧(反正是一道模板题...
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e6+5,inf=1<<29,base=10000;//10000而不是100000,不然容易爆掉! 4 int T; 5 int a[1000],b[1000],c[1000],f[1000]; 6 int read() 7 { 8 int f=1;char ch; 9 while((ch=getchar())<'0'||ch>'9') 10 if(ch=='-')f=-1; 11 int res=ch-'0'; 12 while((ch=getchar())>='0'&&ch<='9') 13 res=res*10+ch-'0'; 14 return res*f; 15 } 16 void write(int x) 17 { 18 if(x<0) 19 { 20 putchar('-'); 21 x=-x; 22 } 23 if(x>9)write(x/10); 24 putchar(x%10+'0'); 25 } 26 /*int gcd(int x,int y) 27 { 28 if(y==0)return x; 29 else return gcd(y,x%y); 30 }*/ 31 //欧几里得算法~显然不行 32 void init(int a[])//压位高精度 33 { 34 string s; 35 cin>>s; 36 int len=s.length(),i,j; 37 for(i=0;i<len;i++) 38 { 39 j=(len-i+3)/4;//注意是len-i+3,而不是+4! 40 a[j]=a[j]*10+s[i]-'0'; 41 } 42 a[0]=(len+3)/4; 43 } 44 int com(int a[],int b[])//比较大小 45 { 46 if(a[0]>b[0])return 1; 47 if(a[0]<b[0])return -1; 48 for(int i=a[0];i>=1;i--) 49 { 50 if(a[i]>b[i])return 1; 51 else if(a[i]<b[i])return -1; 52 } 53 return 0; 54 } 55 void div(int a[])//高精除2 56 { 57 int tmp=0; 58 for(int i=a[0];i>=1;i--) 59 { 60 tmp=tmp*base+a[i]; 61 a[i]=tmp/2; 62 tmp%=2; 63 } 64 while(a[a[0]]==0&&a[0]>0)a[0]--; 65 } 66 void jian(int a[],int b[])//高精减高精 67 { 68 for(int i=1;i<=a[0];i++) 69 { 70 a[i]-=b[i]; 71 if(a[i]<0) 72 { 73 a[i+1]--; 74 a[i]+=base; 75 } 76 while(a[a[0]]==0&&a[0]>0)a[0]--; 77 } 78 } 79 void gcd(int a[],int b[],int t)//二进制算法 80 { 81 if(com(a,b)==0)//如果二者相同,那就是最大公约数无疑了 82 { 83 T=t; 84 return ; 85 } 86 if(com(a,b)<0) 87 { 88 gcd(b,a,t); 89 return ; 90 } 91 int ta=0,tb=0; 92 if(a[1]%2==0) 93 { 94 div(a); 95 ta=1; 96 } 97 if(b[1]%2==0) 98 { 99 div(b); 100 tb=1; 101 } 102 if(ta&&tb)gcd(a,b,t+1); 103 else if(!ta&&!tb) 104 { 105 jian(a,b); 106 gcd(a,b,t); 107 } 108 else gcd(a,b,t); 109 } 110 void print(int a[])//高精输出 111 { 112 write(a[a[0]]); 113 for(int i=a[0]-1;i>0;i--)//这里可是有点学问的,不能直接像输出a[a[0]]一样输出其他几位, 114 for(int j=base/10;j>0;j/=10)//因为其他几位可能最高位为0,直接输出则0被吞掉了 115 write(a[i]/j%10); 116 } 117 void mulow(int a[],int k)//高精乘低精 118 { 119 for(int i=1;i<=a[0];i++)a[i]*=k; 120 for(int i=1;i<=a[0];i++) 121 { 122 a[i+1]+=a[i]/base; 123 a[i]%=base; 124 } 125 while(a[a[0]+1]>0) 126 { 127 a[0]++; 128 a[a[0]+1]=a[a[0]]/base; 129 a[a[0]]%=base; 130 } 131 } 132 void mulhigh(int a[],int b[])//高精乘高精 133 { 134 for(int i=1;i<=a[0];i++) 135 for(int j=1;j<=b[0];j++) 136 { 137 c[i+j-1]+=a[i]*b[j]; 138 c[i+j]+=c[i+j-1]/base; 139 c[i+j-1]%=base; 140 } 141 c[0]=a[0]+b[0]; 142 while(c[c[0]]==0&&c[0]>0)c[0]--; 143 for(int i=0;i<=c[0];i++)a[i]=c[i]; 144 } 145 int main() 146 { 147 init(a);init(b); 148 gcd(a,b,0); 149 if(T==0)print(a);//T存储最大公约数中有多少个2 150 else 151 { 152 f[0]=f[1]=1; 153 for(int i=1;i<=T;i++) 154 mulow(f,2);//将2累乘 155 mulhigh(f,a); 156 print(f); 157 } 158 return 0; 159 }