纪中21日T3 2118. 最大公约数
(File IO): input:gcd.in output:gcd.out
时间限制: 1000 ms 空间限制: 262144 KB 具体限制
题目描述
给出两个正整数A,B,求它们的最大公约数。
输入
第一行一个正整数A。
第二行一个正整数B。
输出
在第一行输出一个整数,表示A,B的最大公约数。
样例输入
1824
样例输出
6
数据范围限制
在40%的数据中,1 ≤ A,B ≤ 10^6
在60%的数据中,1 ≤ A,B ≤ 10^18
在80%的数据中,1 ≤ A,B ≤ 10^100
在100%的数据中,1 ≤ A,B ≤ 10^1000
Solution
Algorithm1
正常的gcd(a,b)=gcd(b,a%b);
开unsigned long long可得六十分(应该不会超时)
Code1
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#define IL inline
using namespace std;
unsigned long long gcd(unsigned long long a,unsigned long long b)
{
return b==0?a:gcd(b,a%b);
}
unsigned long long a,b;
int main()
{
cin>>a>>b;
cout<<gcd(a,b);
return 0;
}
Attention1
函数也要开ULL(缩写)
别把“%”写成“-”,否则在相减前要先使得a>b
而且那样就变成更相减损法了
Algorithm2
gcd二进制法
先看看a,b是不是2的倍数
如果都是,gcd(a,b)=2*gcd(a/2,b/2);
如果a是,gcd(a,b)=gcd(a/2,b);
如果b是,gcd(a,b)=gcd(a,b/2);
如果都不是,gcd(a,b)=gcd(b,a%b)
最后一条=gcd(b,a-b)也可以
(为后面的高精度做铺垫)
Code2

1 #pragma GCC optimize(2)
2 #include<iostream>
3 #include<iomanip>
4 #include<algorithm>
5 #include<cstdio>
6 #include<cstring>
7 #include<cmath>
8 #include<map>
9 #include<set>
10 #include<queue>
11 #include<vector>
12 #define IL inline
13 using namespace std;
14 IL unsigned long long gcdbin(unsigned long long a,unsigned long long b)
15 {
16 if(!b) return a;
17 if(!(a|0)&&!(b|0)) return 2*gcdbin(a>>1,b>>1);
18 if(!(a|0)&&(b&1)) return gcdbin(a>>1,b);
19 if((a&1)&&!(b|0)) return gcdbin(a,b>>1);
20 return gcdbin(b,a%b);
21 }
22 unsigned long long a,b;
23 int main()
24 {
25 freopen("rand_gcd.txt","r",stdin);
26 cin>>a>>b;
27 cout<<gcdbin(a,b);
28 return 0;
29 }
Algorithm3
不压位的高精度
高精度求余数很麻烦(按位求会比较快)
套用更相减损法
同时特判:如果a,b小于19位,依然采用二进制的辗转相除。
Code3

1 #pragma GCC optimize(2)
2 #include<iostream>
3 #include<iomanip>
4 #include<algorithm>
5 #include<cstdio>
6 #include<cstring>
7 #include<cmath>
8 #include<map>
9 #include<set>
10 #include<queue>
11 #include<vector>
12 #define IL inline
13 using namespace std;
14 IL int read()
15 {
16 int res=0;
17 char ch=getchar();
18 while(ch<'0'||ch>'9')
19 ch=getchar();
20 while(ch>='0'&&ch<='9')
21 res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
22 return res;
23 }
24 IL unsigned long long gcdbin(unsigned long long a,unsigned long long b)
25 {
26 if(!b) return a;
27 if(!(a|0)&&!(b|0)) return 2*gcdbin(a>>1,b>>1);
28 if(!(a|0)&&(b&1)) return gcdbin(a>>1,b);
29 if((a&1)&&!(b|0)) return gcdbin(a,b>>1);
30 return gcdbin(b,a%b);
31 }
32 const int L=1001,B=1;
33 string stra,strb;
34 int a[L],b[L],t[L],lena,lenb;
35 unsigned long long ta,tb;
36 bool flag;
37 IL bool cmp()
38 {
39 //if(a<b) return 1;
40 for(int i=L-1;i>=0;i--)
41 {
42 if(a[i]<b[i]) return 1;
43 if(a[i]>b[i]) return 0;
44 }
45 return 0;
46 }
47 int main()
48 {
49 // freopen("gcd.in","r",stdin);
50 // freopen("gcd.out","w",stdout);
51 cin>>stra>>strb;
52 if(stra.size()-1<=19&&strb.size()-1<=19)
53 {
54 for(unsigned int i=0;i<stra.size();i++)
55 if(stra[i]>='0'&&stra[i]<='9')
56 ta=(ta<<1)+(ta<<3)+(stra[i]^48);
57 for(unsigned int i=0;i<strb.size();i++)
58 if(strb[i]>='0'&&strb[i]<='9')
59 tb=(tb<<1)+(tb<<3)+(strb[i]^48);
60 cout<<gcdbin(ta,tb);
61 return 0;
62 }
63 for(unsigned int i=0;i<stra.size();i+=B)
64 a[stra.size()-1-i]=stra[i]-'0';
65 for(unsigned int i=0;i<strb.size();i+=B)
66 b[strb.size()-1-i]=strb[i]-'0';
67 bool fail=1;
68 while(fail)
69 {
70 flag=0;
71 if(cmp())
72 for(int i=L-1;i>=0;i--)
73 {
74 if(a[i]||b[i]) flag=1;
75 if(flag) swap(a[i],b[i]);
76 }
77 //gcd(b,a-b)
78 //t=b
79 flag=0;
80 for(int i=L-1;i>=0;i--)
81 {
82 if(b[i])
83 flag=1;
84 if(flag)
85 t[i]=b[i];
86 }
87 //b=a-b
88 for(int i=0;i<L;i++)
89 {
90 b[i]=a[i]-b[i];
91 if(b[i]<0)
92 {
93 a[i+1]--;
94 b[i]+=10;
95 }
96 }
97 //a=t
98 flag=0;
99 for(int i=L-1;i>=0;i--)
100 {
101 if(t[i]) flag=1;
102 if(flag) a[i]=t[i];
103 }
104
105 //b==0?
106 fail=0;
107 for(int i=0;i<L;i++)
108 {
109 if(b[i]!=0)
110 {
111 fail=1;
112 break;
113 }
114 }
115 }
116 flag=0;
117 bool first=1;
118 for(int i=L-1;i>=0;i--)
119 {
120 if(a[i])
121 flag=1;
122 if(flag){
123 if(!first){
124 for(int i=0;i<B-(int)log10(a[i])-1;i++) printf("0");
125 }
126 first=0;
127 printf("%d",a[i]);
128 }
129
130 }
131 return 0;
132 }
由于是普通的更相减损,一旦数位超过20使用高精,速度就会很慢很慢很慢……
60分~80分不等
Algorithm4
高精压位
核心算法与Algorithm3相同
Code4

1 #pragma GCC optimize(2)
2 #include<iostream>
3 #include<iomanip>
4 #include<algorithm>
5 #include<cstdio>
6 #include<cstring>
7 #include<cmath>
8 #include<map>
9 #include<set>
10 #include<queue>
11 #include<vector>
12 #define IL inline
13 using namespace std;
14 IL int read()
15 {
16 int res=0;
17 char ch=getchar();
18 while(ch<'0'||ch>'9')
19 ch=getchar();
20 while(ch>='0'&&ch<='9')
21 res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
22 return res;
23 }
24 IL unsigned long long gcdbin(unsigned long long a,unsigned long long b)
25 {
26 if(!b) return a;
27 if(!(a|0)&&!(b|0)) return 2*gcdbin(a>>1,b>>1);
28 if(!(a|0)&&(b&1)) return gcdbin(a>>1,b);
29 if((a&1)&&!(b|0)) return gcdbin(a,b>>1);
30 return gcdbin(b,a%b);
31 }
32 const int L=100,B=2;
33 string stra,strb;
34 int a[L],b[L],t[L],lena,lenb;
35 unsigned long long ta,tb;
36 IL bool cmp()
37 {
38 //if(a<b) return 1;
39 for(int i=L-1;i>=0;i--)
40 {
41 if(a[i]<b[i]) return 1;
42 if(a[i]>b[i]) return 0;
43 }
44 return 0;
45 }
46 int main()
47 {
48 // freopen("gcd.in","r",stdin);
49 // freopen("gcd.out","w",stdout);
50 /*
51 a=read();
52 b=read();
53 cout<<gcdbin(ta,tb);
54 */
55 cin>>stra>>strb;
56 for(unsigned int i=stra.size()-1;i>=0;i-=B)
57 {
58 // a[stra.size()-1-i]=stra[i]-'0';
59 for(int j=0;j<B&&i-j>=0;j++)
60 a[lena]+=(stra[i-j]-'0')*pow(10,j);
61 lena++;
62 }
63 for(int i=0;i<lena;i++) swap(a[i],a[lena-i-1]);
64 for(unsigned int i=stra.size()-1;i>=0;i-=B)
65 {
66 // b[strb.size()-1-i]=strb[i]-'0';
67 for(int j=0;j<B&&i-j>=0;j++)
68 b[lenb]+=(strb[i-j]-'0')*pow(10,j);
69 lenb++;
70 }
71 for(int i=0;i<lenb;i++) swap(b[i],b[lenb-i-1]);
72 bool fail=1;
73 while(fail)
74 {
75 if(cmp())
76 for(int i=0;i<L;i++)
77 swap(a[i],b[i]);
78 // /*
79 for(int i=L-1;i>=0;i--)
80 {
81 printf("%d",a[i]);
82 }
83 cout<<endl;
84 for(int i=L-1;i>=0;i--)
85 printf("%d",b[i]);
86 cout<<endl;
87 // */
88 //gcd(b,a-b)
89 //t=b
90 for(int i=L-1;i>=0;i--)
91 t[i]=b[i];
92 //b=a-b
93 for(int i=0;i<L;i++)
94 {
95 b[i]=a[i]-b[i];
96 if(b[i]<0)
97 {
98 a[i+1]--;
99 b[i]+=10;
100 }
101 }
102 //a=t
103 for(int i=L-1;i>=0;i--)
104 a[i]=t[i];
105 //b==0?
106 fail=0;
107 for(int i=0;i<L;i++)
108 {
109 if(b[i]!=0)
110 {
111 fail=1;
112 break;
113 }
114 }
115 }
116 bool flag=0,first=1;
117 for(int i=L-1;i>=0;i--)
118 {
119 if(a[i])
120 flag=1;
121 if(flag){
122 if(!first){
123 for(int i=0;i<B-(int)log10(a[i])-1;i++) printf("0");
124 }
125 first=0;
126 printf("%d",a[i]);
127 }
128
129 }
130 return 0;
131 }
Algorithm5
通过下面(最下面)的对拍发现,四种算法中,二进更相比普通更相更快(不是只有0.3毫秒么?)
高精(可以不压位)二进制更相减损术也不是很难打(而且判断也很快)
Impression
如果你有兴趣……

#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#define IL inline
using namespace std;
unsigned long long gcd(unsigned long long a,unsigned long long b)
{
return b==0?a:gcd(b,a%b);
}
unsigned long long a,b;
int main()
{
freopen("rand_gcd.txt","r",stdin);
cin>>a>>b;
cout<<gcd(a,b);
return 0;
}

#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#define IL inline
using namespace std;
unsigned long long gx(unsigned long long a,unsigned long long b)
{
if(a<b) swap(a,b);
return b==0?a:gx(b,a-b);
}
unsigned long long a,b;
int main()
{
freopen("rand_gcd.txt","r",stdin);
cin>>a>>b;
cout<<gx(a,b);
return 0;
}

#pragma GCC optimize(2)
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#define IL inline
using namespace std;
IL unsigned long long gcdbin(unsigned long long a,unsigned long long b)
{
if(!b) return a;
if(!(a|0)&&!(b|0)) return 2*gcdbin(a>>1,b>>1);
if(!(a|0)&&(b&1)) return gcdbin(a>>1,b);
if((a&1)&&!(b|0)) return gcdbin(a,b>>1);
return gcdbin(b,a%b);
}
unsigned long long a,b;
int main()
{
freopen("rand_gcd.txt","r",stdin);
cin>>a>>b;
cout<<gcdbin(a,b);
return 0;
}

#pragma GCC optimize(2)
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#define IL inline
using namespace std;
IL unsigned long long gxbin(unsigned long long a,unsigned long long b)
{
if(!b) return a;
if(!(a|0)&&!(b|0)) return 2*gxbin(a>>1,b>>1);
if(!(a|0)&&(b&1)) return gxbin(a>>1,b);
if((a&1)&&!(b|0)) return gxbin(a,b>>1);
if(a<b) swap(a,b);
return gxbin(b,a%b);
}
unsigned long long a,b;
int main()
{
freopen("rand_gcd.txt","r",stdin);
cin>>a>>b;
cout<<gxbin(a,b);
return 0;
}

#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<windows.h>
#include<ctime>
#define IL inline
using namespace std;
int main()
{
freopen("rand_gcd.txt","w",stdout);
srand(time(NULL));
cout<<(unsigned long long)rand()*rand()*rand()<<endl;
cout<<(unsigned long long)rand()*rand()*rand()<<endl;
return 0;
}

#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<ctime>
#define IL inline
using namespace std;
int avg[4];
int times;
int main()
{
system("random_gcd.exe");
int s1=clock();
system("gcd.exe");
int s2=clock();
system("gcdbin.exe");
int s3=clock();
system("gx.exe");
int s4=clock();
system("gxbin.exe");
int e=clock();
// cout<<"\n辗转相除:"<<s2-s1<<"ms\n";
// cout<<"二进辗转:"<<s3-s2<<"ms\n";
// cout<<"更相减损:"<<s4-s3<<"ms\n";
// cout<<"二进更相:"<<e-s4<<"ms\n";
avg[0]+=s2-s1;
avg[1]+=s3-s2;
avg[2]+=s4-s3;
avg[3]+=e-s4;
times++;
if(times>=100)
{
system("cls");
cout<<"总计"<<times<<"组数据\n";
cout<<"平均用时:\n";
cout<<"辗转相除:"<<avg[0]/(times*1.0)<<"ms\n";
cout<<"二进辗转:"<<avg[1]/(times*1.0)<<"ms\n";
cout<<"更相减损:"<<avg[2]/(times*1.0)<<"ms\n";
cout<<"二进更相:"<<avg[3]/(times*1.0)<<"ms\n";
return 0;
}
main();
return 0;
}
1000组数据运算结果如下

End
