zoukankan      html  css  js  c++  java
  • 关于gcd和exgcd的一点心得,保证看不懂(滑稽)

    网上看了半天……还是没把欧几里得算法和扩展欧几里得算法给弄明白……

    然后想了想自己写一篇文章好了……

    参考文献:https://www.cnblogs.com/hadilo/p/5914302.html

        https://blog.csdn.net/sky_zdk/article/details/71023325

        《算法竞赛进阶指南》(李煜东)(我不是来推销的)

    ps:本文讨论范围均在整数以内

    一、欧几里得算法

        欧几里得算法,即辗转相除法,简称gcd,用于计算两个数的最大公约数。时间复杂度据说log n的

        公式 gcd(a,b)=gcd(b,a mod b) ,b≠0

        啥?证明?能用就行要什么证明

        咳咳,让我们来严格的证明一下

        证:

          若a<b,以上等式显然成立

          若a>=b, 设a=q*b+r,0<=r<b, 即r=a%b 。对于a,b的任意公约数d,因为d|a(ps:这个符号的意思是d是a的约数),d|b,所以d|q*b,可得d|(a-q*b),即d|r,d也是r的约数。反之亦成立。所以,a,b的公约数集合和b,a mod b的公约数集合相同,他们的最大公约数自然也相同。

        证毕

    上代码(我知道你们只想要这个)

    int gcd(int a,int b){
        return b?gcd(b,a%b):a;
    }

    当然还有更装逼别致的写法

    int gcd(int a,int b){
        if(!b) return a;
        while(b^=a^=b^=a%=b);//先做一次取模,然后交换两个元素
        return a;
    }

         ps:问题就是取模太慢了,有的题目可能用更相减损法还更快……所以更相减损大法好(口胡)<---别听这家伙瞎说,时间复杂度根本不一样

    二、扩展欧几里得算法

        一个很厉害的东西,我看了半天没弄明白(队长好像一看就懂)

        引理:裴蜀定理,一定存在ax+by=gcd(a,b)的整数解

        乱证严格的证明:

          当b=0时,gcd(a,b)=a,显然存在一对整数解x=1,y=0

          若b!=0

          设ax1+by1=gcd(a,b)=gcd(b,a%b)=bx2+(a%b)y2

          又因 a%b=a-a/b*b

          则 ax1+by1=bx2+(a-a/b*b)y2

          ax1+by1=bx2+ay2-a/b*by2

          ax1+by1=ay2+bx2-b*a/b*y2

          ax1+by1=ay2+b(x2-a/b*y2)

          解得 x1=y2 , y1=x2-a/b*y2

          因为当 b=0 时存在 x , y 为最后一组解

          而每一组的解可根据后一组得到

          所以第一组的解 x , y 必然存在

        证毕

        然后递归计算就可以,当b=0时,返回x=1,y=0即可

    上代码

    int exgcd(int a,int b,int &x,int &y){
        //注意x和y必须是引用 
        if(!b){x=1,y=0;return a;}
        int d=exgcd(b,a%b,x,y);
        int t=x;x=y,y=t-(a/b)*y;
        return d;//d是a和b的gcd,顺便求出来 
    }

    san三、扩欧解不定方程

          对于形如ax+by=c的方程

          先用exgcd求出ax+by=gcd(a,b)的一组解x0,x1

          根据裴蜀定理(上面那个),如果c%gcd(a,b)==0,此方程有解,否则无解

          若有解

          设d=gcd(a,b)

          令方程两边同乘上c/d

          则方程变为(a*c/d)x0+(b*c/d)y0=c

          于是我们就得到了一组解了,x1=x0*c/d,y1=y0*c/d

          然后就学不下去了orz……但问题是还没完QAQ

          题目里面,一般不可能让你只求出一组解,一般都是要你求出最小整数解

          保佑自己上面算出来的刚好是答案就好了,只要够欧就没问题

          认真点

          求最小整数解,就是把x1减小到不能减小为止,再看看上面的式子,c和d都是定值,于是我们只要考虑把x0减小到不能减小为止

          设x0减小x,方程左边总体减小x*c/d*a,为了保证等式成立,y0增加的值y应满足x*c/d*a=y*c/d*b

          于是x/y=(b/d) / ( a/d)

          我们令x0不断减x(x=b/d),直到0<=x1<x,此时的x1即为最小整数解

          我们可以令x1=x0%x,就可以算出x1了

          等等,真的大丈夫?

          如果x0是负数怎么办?我们让x1+x就可以得到正数了

          如果x是负数呢?令x=abs(x)即可

          关于以两点,请自行考虑(才不是因为我也不会呢)

    上代码啦

    d=exgcd(a,b,x,y);
    if(c%d==0)
    { 
        x*=c/d; 
        t=b/d;
        t=abs(t);
        x=(x%t+t)%t;
        printf("%d
    ",x); 
    }

    四、解线性同余方程

        这个随便提一嘴吧,因为我也不太会

          对于ax≡c(mod p)

          将其转化为ax+py=c

          然后带进上面求解,一般都是要求出x的最小整数解的

    emm……差不多了,就这样吧

    以上

    深深地明白自己的弱小
  • 相关阅读:
    B-Suffix Array
    1 or 2
    Boundary
    Fake Maxpooling
    Cover the Tree
    Omkar and Circle
    20.5.31
    Yet Another Yet Another Task
    Codeforces Round #373 (Div. 2)E. Sasha and Array +线段树+矩阵快速幂
    2018 Multi-University Training Contest 2(Naive Operations ) hdu6315
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9321594.html
Copyright © 2011-2022 走看看