gcd以及ex_gcd的总结
转载连接: http://www.xuebuyuan.com/552599.html
ex_gcd()---表示扩展欧几里得算法
gcd()---表示最大公约数,常用方法是欧几里得算法
定义1:a和b是两个不全为0的整数,称a与b的公因子中最大的为a和b的最大公约数,用gcd(a,b)来表示。
定义2:a和b是两个非0的整数,称a与b的公倍数中最小的为a和b的最小公倍数,用lcm(a,b)来表示。
最小公倍数与最大公约数之间的性质:
1、若a|m,b|m,那么lcm(a,b)|m
2、若d|a,d|b,则d|gcd(a,b)
3、lcm(a,b)=a/gcd(a,b)*b
4、设m,a,b是正整数,则lcm(ma,mb)=m*gcd(a,b)
5、若m是非0整数,a1,a2……an的公倍数,则lcm(a1,a2……an)|m
6、整数a和b素因子分解成a=p1^(r1)*p2^(r2)……pn^(rn),b=p1^(s1)*p2^(s2)……pn^(sn),在这儿·pi是不同的素数
gcd(a,b)=p1^min(r1,s1)*p2^min(r2,s2)*……pn^min(rn,sn)
lcm(a,b)=p1^max(r1,s1)*p2^max(r2,s2)*……pn^max(rn,sn)
gcd的求解思路----辗转相除法
递归求解
- int gcd(int m,int n)
- {
- if(n==0)
- return m;
- else
- return gcd(n,m%n);
- }
迭代求解
- int gcd(int m,int n)
- {
- int temp;
- if(m<n)
- {
- swap(m,n);
- }
- while((temp=m%n)!=0)
- {
- m=n;
- n=temp;
- }
- return n;
- }
HDU1222
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1222
题意:假设步长是m 总长度是N, 这里首先我们计算出他们的周期,也就是最小公倍数,当过了这个周期,狼搜索的点肯定重复了!
因为狼每走一次肯定是搜索了一个点,搜索完n个点的时候,走的长度正好是这个周期,说明他没有重复的搜索了N个点!这就转化到gcd
- #include<iostream>
- #include<cstdio>
- #include<cmath>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- /*
- int gcd(int m,int n)
- {
- int temp;
- if(m<n)
- {
- swap(m,n);
- }
- while((temp=m%n)!=0)
- {
- m=n;
- n=temp;
- }
- return n;
- }
- */
- int gcd(int m,int n)
- {
- if(n==0)
- return m;
- else
- return gcd(n,m%n);
- }
- int main()
- {
- int m,n;
- int T;
- scanf("%d",&T);
- while(T--)
- {
- scanf("%d%d",&m,&n);
- if(gcd(m,n)==1)
- printf("NO\n");
- else
- printf("YES\n");
- }
- return 0;
- }
HDU1108
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1108
题意:很简单,就是求最小公倍数,利用性质3就可以
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<cmath>
- using namespace std;
- int gcd(int a,int b)
- {
- if(b==0)
- return a;
- else
- return gcd(b,a%b);
- }
- int main()
- {
- int a,b;
- int k;
- while(cin>>a>>b)
- {
- k=a*b/gcd(a,b);
- cout<<k<<endl;
- }
- return 0;
- }
扩展欧几里得算法:
在通过循环就可以写出代码
- long long ex_gcd(long long a,long long b,long long &x,long long &y)
- {
- if(b==0)
- {
- x=1;
- y=0;
- return a;
- }
- long long r=ex_gcd(b,a%b,x,y);
- long long t=x;
- x=y;
- y=t-a/b*y;
- return r;
- }
HDU4180
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4180
题意: 给出分数(a/b)求另一个分数(c/d){d < b),且满足fabs(a/b - c/d)最小。 ab互质时 最小时满足 bc+1 = ad || bc = ad+1,正符合扩展欧几里得。求出两个d后比较。
- #include<iostream>
- #include<cstdio>
- using namespace std;
- int ex_gcd(int a,int b,int &x,int &y)
- {
- if(b==0)
- {
- x=1;
- y=0;
- return a;
- }
- int r=ex_gcd(b,a%b,x,y);
- int t=x;
- x=y;
- y=t-a/b*y;
- return r;
- }
- int main()
- {
- int t;
- cin>>t;
- int a,b;
- int x,y;
- while(t--)
- {
- scanf("%d/%d",&a,&b);
- int gcd=ex_gcd(a,b,x,y);
- if(gcd!=1)
- {
- printf("%d/%d\n",a/gcd,b/gcd);
- continue;//这儿必须要写啊 不然会wa的
- }
- if(a==1)
- {
- printf("%d/%d\n",a,b-1);
- continue;
- }
- int c1=(-y+a)%a;
- int c2=(y+a)%a;
- int d1=(x+b)%b;
- int d2=(-x+b)%b;
- if(d1<d2)
- printf("%d/%d\n",c2,d2);
- else
- printf("%d/%d\n",c1,d1);
- }
- return 0;
- }
POJ1061
题目连接:http://poj.org/problem?id=1061
题意:两只青蛙跳了t步,A的坐标为x+m*t,B的坐标为y+n*t,他们相遇的条件为:x+m*t-y-n*t=p*L,即得到:(n-m)*t+L*p=(x-y)
这时求最小的t就是解一次同余方程(n-m)*t+L*p=(x-y)的最小整数解
- #include<cstdio>
- #include<algorithm>
- #include<iostream>
- #include<cmath>
- using namespace std;
- long long gcd(long long a,long long b)
- {
- if(!b)return a;
- else return gcd(b,a%b);
- }
- void ex_gcd(long long a,long long b,long long &x,long long &y)
- {
- if(b==0)
- {
- x=1;
- y=0;
- return ;
- }
- ex_gcd(b,a%b,x,y);
- long long t=x;
- x=y;
- y=t-a/b*y;
- }
- int main()
- {
- long long x,y,m,n,l;
- long long k1,k2;
- long long t;
- long long a,b,c,g;
- while(cin>>x>>y>>m>>n>>l)
- {
- a=n-m;
- b=l;
- c=x-y;
- g=gcd(a,b);
- if(c%g)
- {
- cout<<"Impossible"<<endl;
- continue;
- }
- a=a/g;
- b=b/g;
- c=c/g;
- ex_gcd(a,b,k1,k2);
- t=c*k1/b;
- k1=c*k1-b*t;
- if(k1<0)
- k1+=b;
- cout<<k1<<endl;
- }
- return 0;
- }
扩展欧几里得算法应用比较广泛,很多算法都用到了它,比如说同余问题等等
欧几里得算法比较适合于__int64范围内数,但是对于很大的数就不适合了,在这儿介绍一种适合大数的求最大公约数的算法,它的名字就是Stein算法,它是对欧几里得算法的一种改进,适合超过64位的整数,它只有移位和加法操作,它的算法思想就是
gcd(a,a)=a, gcd(k*a,k*b)=k*gcd(a,b)
当k与b互素时,gcd(k*a,b)=gcd(a,b);
算法步骤:
1、如果a=b,那么a或者b是最大公约数,算法结束
2、如果a=0,b是最大公约数,算法结束
3、如果b=0,a是最大公约数,算法结束
4、设置a[1]=a,b[1]=b和c[1]=1
5、如果a[n]和b[n]都是偶数,则a[n+1]=a[n]/2,b[n+1]=b[n]/2,c[n+1]=c[n]*2
6、如果a[n]是偶数,b[n]不是,则a[n+1]=a[n]/2,b[n+1]=b[n],c[n+1]=c[n]
7、如果b[n]是偶数,a[n]不是,则a[n+1]=a[n],b[n+1]=b[n]/2,c[n+1]=c[n]
8、如果a[n]和b[n]都不是偶数,则a[n+1]=abs(a[n]-b[n])/2,b[n+1]=min(a[n],b[n]),c[n+1]=c[n]
9、n++,转到1
- #include<iostream>
- #include<cmath>
- #include<cstdio>
- #include<algorithm>
- using namespace std;
- __int64 Stein(__int64 a,__int64 b)
- {
- if(a<b)swap(a,b);
- if(b==0)return a;
- if((a%2==0)&&(b%2==0))return 2*Stein(a/2,b/2);
- if(a%2==0)return Stein(a/2,b);
- if(b%2==0)return Stein(a,b/2);
- return Stein((a-b)/2,b);
- }
- int main()
- {
- __int64 a,b;
- while(cin>>a>>b)
- {
- cout<<Stein(a,b)<<endl;
- }
- return 0;
- }
ex_gcd()---表示扩展欧几里得算法
gcd()---表示最大公约数,常用方法是欧几里得算法
定义1:a和b是两个不全为0的整数,称a与b的公因子中最大的为a和b的最大公约数,用gcd(a,b)来表示。
定义2:a和b是两个非0的整数,称a与b的公倍数中最小的为a和b的最小公倍数,用lcm(a,b)来表示。
最小公倍数与最大公约数之间的性质:
1、若a|m,b|m,那么lcm(a,b)|m
2、若d|a,d|b,则d|gcd(a,b)
3、lcm(a,b)=a/gcd(a,b)*b
4、设m,a,b是正整数,则lcm(ma,mb)=m*gcd(a,b)
5、若m是非0整数,a1,a2……an的公倍数,则lcm(a1,a2……an)|m
6、整数a和b素因子分解成a=p1^(r1)*p2^(r2)……pn^(rn),b=p1^(s1)*p2^(s2)……pn^(sn),在这儿·pi是不同的素数
gcd(a,b)=p1^min(r1,s1)*p2^min(r2,s2)*……pn^min(rn,sn)
lcm(a,b)=p1^max(r1,s1)*p2^max(r2,s2)*……pn^max(rn,sn)
gcd的求解思路----辗转相除法
递归求解
- int gcd(int m,int n)
- {
- if(n==0)
- return m;
- else
- return gcd(n,m%n);
- }
迭代求解
- int gcd(int m,int n)
- {
- int temp;
- if(m<n)
- {
- swap(m,n);
- }
- while((temp=m%n)!=0)
- {
- m=n;
- n=temp;
- }
- return n;
- }
HDU1222
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1222
题意:假设步长是m 总长度是N, 这里首先我们计算出他们的周期,也就是最小公倍数,当过了这个周期,狼搜索的点肯定重复了!
因为狼每走一次肯定是搜索了一个点,搜索完n个点的时候,走的长度正好是这个周期,说明他没有重复的搜索了N个点!这就转化到gcd
- #include<iostream>
- #include<cstdio>
- #include<cmath>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- /*
- int gcd(int m,int n)
- {
- int temp;
- if(m<n)
- {
- swap(m,n);
- }
- while((temp=m%n)!=0)
- {
- m=n;
- n=temp;
- }
- return n;
- }
- */
- int gcd(int m,int n)
- {
- if(n==0)
- return m;
- else
- return gcd(n,m%n);
- }
- int main()
- {
- int m,n;
- int T;
- scanf("%d",&T);
- while(T--)
- {
- scanf("%d%d",&m,&n);
- if(gcd(m,n)==1)
- printf("NO\n");
- else
- printf("YES\n");
- }
- return 0;
- }
HDU1108
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1108
题意:很简单,就是求最小公倍数,利用性质3就可以
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<cmath>
- using namespace std;
- int gcd(int a,int b)
- {
- if(b==0)
- return a;
- else
- return gcd(b,a%b);
- }
- int main()
- {
- int a,b;
- int k;
- while(cin>>a>>b)
- {
- k=a*b/gcd(a,b);
- cout<<k<<endl;
- }
- return 0;
- }
扩展欧几里得算法:
在通过循环就可以写出代码
- long long ex_gcd(long long a,long long b,long long &x,long long &y)
- {
- if(b==0)
- {
- x=1;
- y=0;
- return a;
- }
- long long r=ex_gcd(b,a%b,x,y);
- long long t=x;
- x=y;
- y=t-a/b*y;
- return r;
- }
HDU4180
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4180
题意: 给出分数(a/b)求另一个分数(c/d){d < b),且满足fabs(a/b - c/d)最小。 ab互质时 最小时满足 bc+1 = ad || bc = ad+1,正符合扩展欧几里得。求出两个d后比较。
- #include<iostream>
- #include<cstdio>
- using namespace std;
- int ex_gcd(int a,int b,int &x,int &y)
- {
- if(b==0)
- {
- x=1;
- y=0;
- return a;
- }
- int r=ex_gcd(b,a%b,x,y);
- int t=x;
- x=y;
- y=t-a/b*y;
- return r;
- }
- int main()
- {
- int t;
- cin>>t;
- int a,b;
- int x,y;
- while(t--)
- {
- scanf("%d/%d",&a,&b);
- int gcd=ex_gcd(a,b,x,y);
- if(gcd!=1)
- {
- printf("%d/%d\n",a/gcd,b/gcd);
- continue;//这儿必须要写啊 不然会wa的
- }
- if(a==1)
- {
- printf("%d/%d\n",a,b-1);
- continue;
- }
- int c1=(-y+a)%a;
- int c2=(y+a)%a;
- int d1=(x+b)%b;
- int d2=(-x+b)%b;
- if(d1<d2)
- printf("%d/%d\n",c2,d2);
- else
- printf("%d/%d\n",c1,d1);
- }
- return 0;
- }
POJ1061
题目连接:http://poj.org/problem?id=1061
题意:两只青蛙跳了t步,A的坐标为x+m*t,B的坐标为y+n*t,他们相遇的条件为:x+m*t-y-n*t=p*L,即得到:(n-m)*t+L*p=(x-y)
这时求最小的t就是解一次同余方程(n-m)*t+L*p=(x-y)的最小整数解
- #include<cstdio>
- #include<algorithm>
- #include<iostream>
- #include<cmath>
- using namespace std;
- long long gcd(long long a,long long b)
- {
- if(!b)return a;
- else return gcd(b,a%b);
- }
- void ex_gcd(long long a,long long b,long long &x,long long &y)
- {
- if(b==0)
- {
- x=1;
- y=0;
- return ;
- }
- ex_gcd(b,a%b,x,y);
- long long t=x;
- x=y;
- y=t-a/b*y;
- }
- int main()
- {
- long long x,y,m,n,l;
- long long k1,k2;
- long long t;
- long long a,b,c,g;
- while(cin>>x>>y>>m>>n>>l)
- {
- a=n-m;
- b=l;
- c=x-y;
- g=gcd(a,b);
- if(c%g)
- {
- cout<<"Impossible"<<endl;
- continue;
- }
- a=a/g;
- b=b/g;
- c=c/g;
- ex_gcd(a,b,k1,k2);
- t=c*k1/b;
- k1=c*k1-b*t;
- if(k1<0)
- k1+=b;
- cout<<k1<<endl;
- }
- return 0;
- }
扩展欧几里得算法应用比较广泛,很多算法都用到了它,比如说同余问题等等
欧几里得算法比较适合于__int64范围内数,但是对于很大的数就不适合了,在这儿介绍一种适合大数的求最大公约数的算法,它的名字就是Stein算法,它是对欧几里得算法的一种改进,适合超过64位的整数,它只有移位和加法操作,它的算法思想就是
gcd(a,a)=a, gcd(k*a,k*b)=k*gcd(a,b)
当k与b互素时,gcd(k*a,b)=gcd(a,b);
算法步骤:
1、如果a=b,那么a或者b是最大公约数,算法结束
2、如果a=0,b是最大公约数,算法结束
3、如果b=0,a是最大公约数,算法结束
4、设置a[1]=a,b[1]=b和c[1]=1
5、如果a[n]和b[n]都是偶数,则a[n+1]=a[n]/2,b[n+1]=b[n]/2,c[n+1]=c[n]*2
6、如果a[n]是偶数,b[n]不是,则a[n+1]=a[n]/2,b[n+1]=b[n],c[n+1]=c[n]
7、如果b[n]是偶数,a[n]不是,则a[n+1]=a[n],b[n+1]=b[n]/2,c[n+1]=c[n]
8、如果a[n]和b[n]都不是偶数,则a[n+1]=abs(a[n]-b[n])/2,b[n+1]=min(a[n],b[n]),c[n+1]=c[n]
9、n++,转到1
- #include<iostream>
- #include<cmath>
- #include<cstdio>
- #include<algorithm>
- using namespace std;
- __int64 Stein(__int64 a,__int64 b)
- {
- if(a<b)swap(a,b);
- if(b==0)return a;
- if((a%2==0)&&(b%2==0))return 2*Stein(a/2,b/2);
- if(a%2==0)return Stein(a/2,b);
- if(b%2==0)return Stein(a,b/2);
- return Stein((a-b)/2,b);
- }
- int main()
- {
- __int64 a,b;
- while(cin>>a>>b)
- {
- cout<<Stein(a,b)<<endl;
- }
- return 0;
- }