一、辗转相除法
gcd(a,b)=gcd(b,a%b)
二、二进制算法优化
若x=y,则gcd(x,y)=x,否则:
①若x,y均为偶数,则gcd(x,y)=2*gcd(x/2,y/2);
②若x为奇数,y为偶数,则gcd(x,y)=2*gcd(x,y/2);
③若x为偶数,y为奇数,则gcd(x,y)=2*gcd(x/2,y);
④若x,y均为奇数,则gcd(x,y)=gcd(x-y,y);
代码实现
int gcd(int x,int y) { int i,j; if(x==0)return y; if(y==0)return x; for(i=0;!(x&1);i++)x>>=1; for(j=0;!(y&1);j++)y>>=1; if(j<i)i=j; while(1) { if(x<y)x^=y,y^=x,x^=y; x-=y; if(x==0)return y<<i; while(!(x&1))x>>=1; } }
三、最小公倍数
LCM(a,b)×GCD(a,b)=a×b
四、扩展欧几里得算法
首先我们有结论:ax+by=c的充分必要条件是gcd(a,b)|c
所以我们可以用扩展欧几里得定理来求解一组ax+by=gcd(a,b)的解
∵gcd(a,b)=gcd(b,a%b)
∴ax+by=gcd(a,b)=gcd(b,a%b)=bx+(a%b)y=bx+(a-a/b*b)y=ay+(x-a/b*y)b
因此就可以得到x、y的转移等式,而b=0时显然x=1,y=0。
五、求解线性同余方程
对于不定方程ax+by=c,等价于ax≡c(mod b),所以当我们用扩展欧几里得定理求出一组特解x0、y0后,通解为:
x=x0+b*t,y=y0-a*t,其中t为任意整数。
而对于最小正整数解,设t=b/gcd(a,b),x=(x%t+t)%t。
例1:
欧几里得的游戏
有两个数M、N,每次可以将大的数减去小的数的正整数倍,先得到0的人获胜,给出M、N,求先手胜还是后手胜。
首先我们考虑特例,这里假设所有M>N:
①如果M%N=0,那么显然先手胜。
②如果M%N≠0,那么显然(M,N)这个状态可以转移到(M-N*K,N),极限状态为(N,M%N),这样就相当于又开了一局游戏。而对于每一种极限状态,我们都可知N<M<N*2,所以我们可以考虑取到(M%N+N,N),那么就保证每一次自己操作都是极限状态,而对于结束状态一定是极限状态,所以在两个人都按最优策略取时,胜方必定可以保证自己每次都取到极限状态,所以相当于做一次欧几里得算法。
代码
#include<bits/stdc++.h> using namespace std; int main() { int t; scanf("%d",&t); while(t--) { int m,n; scanf("%d%d",&m,&n); if(m<n)m^=n,n^=m,m^=n; bool f=1; while(m/n==1&&m%n!=0) { int t=m%n;m=n;n=t; f^=1; } if(f)printf("Stan wins\n"); else printf("Ollie wins\n"); } }