關於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\n",x); 
}

 

四、解線性同余方程

    這個隨便提一嘴吧,因為我也不太會

      對於ax≡c(mod p)

      將其轉化為ax+py=c

      然后帶進上面求解,一般都是要求出x的最小整數解的

emm……差不多了,就這樣吧

以上

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM