最大公约数

一、辗转相除法

  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");
    }
}
posted @ 2019-10-22 22:01  fbz  阅读(124)  评论(0编辑  收藏  举报