纪中21日T3 2118. 【2016-12-30普及组模拟】最大公约数

痞子三分冷 提交于 2019-11-28 03:35:43

纪中21日T3 2118. 最大公约数

(File IO): input:gcd.in output:gcd.out

时间限制: 1000 ms  空间限制: 262144 KB  具体限制  

Goto ProblemSet

题目描述

给出两个正整数A,B,求它们的最大公约数。

输入

第一行一个正整数A。
第二行一个正整数B。

输出

在第一行输出一个整数,表示A,B的最大公约数。

样例输入

1824 

样例输出

数据范围限制

在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 }
Code2

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 }
Code3

由于是普通的更相减损,一旦数位超过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 }
Code4

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;
}
gcd.cpp
#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;
}
gx.cpp
#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;
}
gcdbin
#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;
}
gxbin.cpp
#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;
}
rand_gcd.cpp
#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;
}
gcd对拍.cpp

1000组数据运算结果如下

End

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!