1. 程式人生 > >數論雜談——歐幾裏得算法及擴展歐幾裏得

數論雜談——歐幾裏得算法及擴展歐幾裏得

區別 數據 原來 bottom noip clas 技術分享 code 它的

數學是oi的重要基礎,所以說數論在oi中占據了非常重要的地位,因此,學好數學,對於一個oier來說也是非常重要的。

oi中的數學,其實也就和數競並沒有什麽區別。

歐幾裏得法輾轉相除法求最大公約數 我們可以證明gcd(a,b)=gcd(b,a%b),也就是我國古代數學智慧的結晶,更相損減術。並且一直遞歸下去,直到b的值為零,最大公約數值即為a。在這裏就不給出詳細證明了,大家可以代幾個數據去驗證它一下。誰叫我數學太菜。

代碼如下

技術分享圖片
int GCD(int a,int b)
{
    if(!b)
    {
        return a;
    }
    else
{ return (b,a%b); } }
View Code

其實講了這麽多,我們還是為了引出擴展歐幾裏得算法,也是基於輾轉相除法的基礎,對此我們就可以求得不定方程ax+by=gcd(a,b)的一組特殊解。

這個方程也可以等價於ax≡gcd(a,b)(mod b)也就是我們所說的同余方程。

我們還可以通過此得出一種性質,那就是bx‘+a%by‘=gcd(b,a%b)=ax+by=gcd(a,b)。也就和輾轉相除法聯系起來了。

所以我們再把a%b展開,就可以得到a%b=a-a/b,再把它代入原式得bx‘+(a-a/b)y‘=bx‘+ay‘-a/b*y‘=ay‘+bx‘-a/b*y。我們可以發現,在原來的位置上(ax+by),可以等效於x=y‘,y=x-(a/b*y)。因此我們只要知道一個解便可以推出。

代碼如下

int Exgcd(int a,int &x,int b,int &y)//‘&’符號便於我們直接修改x和y的值
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;//相當於求一個gcd的過程
    }
    int ans=Exgcd(b,x,a%b,y);//求解方程
    int tmp;//用來保存上一個x的值
    x=y;
    y=tmp-(a/b)*y;//我們剛才推出的式子
    return ans;
}

然而,你以為這樣就完了嗎?

別高興的太早,我們上面的方程只是求的ax+by=gcd(a,b)的一組特殊解

但往往惡心的出題人會讓你求諸如ax+by=c的特殊情況

所以僅僅有一個擴展歐幾裏得是不夠的

我們現在就以Noip提高組2012年的"同余方程"為例

題目見洛谷P1082

其實也是一道擴展歐幾裏得的模板題

但他是讓我們求關於xx的同余方程ax1(mod b) 的最小正整數解。

還是我們先求出ax+by=gcd(a,b)的解,用裸的擴展歐幾裏得即可

然後這個同余方程可以看做ax+by=1;

好吧是我看錯了

題目中的數據都是滿足互質的情況,所以gcd(a,b)一定是1。

那我們怎樣來找它的最小整數解呢

那麽取模就非常重要了!

取模就是將一個隨機的值摸到相應的一個區間中

所以說我們求他的最小整數解就可以用這樣一個公式來解決

ans=(x*(c/gcd(a,b))%abs(b/gcd(a,b))+abs(b/gcd(a,b)))%gcd(b/gcd(a,b))

數論雜談——歐幾裏得算法及擴展歐幾裏得