歐幾里德&&擴展歐幾里德

歐幾里得算法:
遞歸版本:

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

迭代版本:

int gcd(int a,int b)
{
    while(b!=0)
    {
        int r=b;
        b=a%b;
        a=r;
    }
    return a;
}

擴展歐幾里德算法:
基本算法:對于不完全為 0 的非負整數 a,b,gcd(a,b)表示 a,b 的最大公約數,必然存在整數對 x,y ,使得 gcd(a,b)=ax+by。

證明:設 a>b。
  1,顯然當 b=0,gcd(a,b)=a。此時 x=1,y=0;
  2,ab!=0 時
  設 ax1+by1=gcd(a,b);
  bx2+(a mod b)y2=gcd(b,a mod b);
  根據樸素的歐幾里德原理有 gcd(a,b)=gcd(b,a mod b);
  則:ax1+by1=bx2+(a mod b)y2;
  即:ax1+by1=bx2+(a-(a/b)b)y2=ay2+bx2-(a/b)*by2;
  根據恒等定理得:x1=y2; y1=x2-(a/b)y2;
這樣我們就得到了求解 x1,y1 的方法:x1,y1 的值基于 x2,y2.

int exgcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    int res=exgcd(b,a%b,x,y);
    int temp=x;
    x=y;
    y=temp-a/b*y;
    return res;
}

擴展歐幾里德算法的應用主要有以下三方面:
(1)求解不定方程;
(2)求解模線性方程(線性同余方程);
(3)求解模的逆元;

(1)使用擴展歐幾里德算法解決不定方程的辦法:
對于不定整數方程a*x+b*y=c,若 c mod Gcd(x, y)=0,則該方程存在整數解,否則不存在整數解。 上面已經列出找一個整數解的方法,在找到 a*x+ b*y = Gcd(a,b)的一組解x0,y0后,
a*x+b*y = Gcd(a, b)的其他整數解滿足:
x = x0 + b/Gcd(a, b) * t
y = y0 - a/Gcd(a, b) * t(其中t為任意整數)
因為a*x+b*y=a(x0 + b/Gcd(a, b) * t)+b(y0 - a/Gcd(a, b) * t)=Gcd(a,b)

其中,最小的正整數x為: x=x0%( b/Gcd(a, b) )
最小的正整數y: y=y0%( a/Gcd(a, b) )

至于ax+by=c的整數解,只需將a*x+b*y= Gcd(a,b)的每個解乘上 c/Gcd(a,b) 即可。

用擴展歐幾里得算法解不定方程ax+by=c;

bool linear_equation(int a,int b,int c,int &x,int &y)
{
    int d=exgcd(a,b,x,y);
    if(c%d)
        return false;
    int k=c/d;
    x*=k; y*=k;    //初解
  /*
  x=x+b/(gcd(a,b))*t;//其他解
  y=y-a/(gcd(a,b))*t;
  t為任意整數
  */
    return true;
}

(2)用擴展歐幾里德算法求解模線性方程的方法:
同余方程 ax≡b (mod n),即(a*x-b) mod n=0;推出a*x+n*y=b;所以轉化為求不定方程a*x+n*y=Gcd(a,n)。
如果b%(Gcd(a,n))!=0,那么方程無整數解;否則求出初解x0,然而初值還要乘以b/Gcd(a,n),即x=x0*b/Gcd(a,n)才是方程a*x+n*y=b的解
而其他整數解則滿足:
x(i) = x + b/Gcd(a, b) * t
y(i) = y - a/Gcd(a, b) * t (其中t為任意整數)

bool modular_linear_equation(int a,int b,int n)
{
    int x,y,x0,i;
    int d=exgcd(a,n,x,y);
    if(b%d)
        return false;
    x0=x*(b/d)%n;   //特解
    for(i=1;i<d;i++)
        printf("%d\n",(x0+i*(n/d))%n);
    return true;
}

(3)用歐幾里德算法求模的逆元:
乘法逆元:如果a*x≡1 (mod p),且gcd(a,p)=1(a與p互質),則稱a關于模p的乘法逆元為x。
它的同余方程ax+py=gcd(a,p)=1,而1%1==0,所以肯定有解

LL exgcd(LL a,ll b,LL &x,LL &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    ll gcd=exgcd(b,a%b,x,y);
    ll temp=x;
    x=y;
    y=temp-a/b*y;
    return gcd;
}
LL reverseMod(LL a,LL mod)
{
    LL x,y;
    LL d=exgcd(a,mod,x,y);//求初解x
    //其他解為x(i) = x+b/Gcd(a, b)*t=x+mod/1*t=x+mod*t
    while(x<0) x+=mod;//求出一個x>0的逆元
    return x;

} 

( 4 )用費馬小定理求乘法逆元。
由費馬小定理a^(p-1)≡ 1(mod p)(p為素數),稍作變形即是 a*a^(p-2)≡ 1(mod p),是不是發現了,a^(p-2)即是a的逆元,這個可以用快速冪來求。

typedef long long LL;
LL fast_multi(LL a,LL b,LL mod)
{
    LL res=0,base=a;
    while(b)
    {
        if(b&1) res=(res+base)%mod;
        b>>=1;
        base=(base+base)%mod;
    }
    return res;
}
LL pow_mod(LL a,LL b,LL mod)
{
    LL res=1,base=a;
    while(b)
    {
        if(b&1) res=fast_multi(res,base,mod);
        base=fast_multi(base,base,mod);
        b>>=1;
    }
    return res;
}//b關于對mod取模的逆元為pow_mod(b,mod-2,mod);

題目:求(a/b)%mod。
題解:先求出b的逆元,然后結果為(a*(b^-1) )%mod,b^-1指b關于對mod取模運算的逆元

#include<stdio.h>
#include <string.h>
using namespace std;
const long long mod=9973;//一個素數
typedef long long LL;
LL fast_multi(LL a,LL b,LL mod)
{
    LL res=0,base=a;
    while(b)
    {
        if(b&1) res=(res+base)%mod;
        b>>=1;
        base=(base+base)%mod;
    }
    return res;
}
LL pow_mod(LL a,LL b,LL mod)
{
    LL res=1,base=a;
    while(b)
    {
        if(b&1) res=fast_multi(res,base,mod);
        base=fast_multi(base,base,mod);
        b>>=1;
    }
    return res;
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    LL gcd=exgcd(b,a%b,x,y);
    LL temp=x;
    x=y;
    y=temp-a/b*y;
    return gcd;
}
LL reverseMod(LL a,LL mod)
{
    LL x,y;
    LL d=exgcd(a,mod,x,y);
    while(x<0) x+=mod;
    return x;

}
int main()
{
    int n;
    LL a,b,x;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%lld%lld",&a,&b);
        x=reverseMod(b,mod);
        printf("%lld\n",fast_multi(a,x,mod));//擴展歐里幾德
        printf("%lld\n",fast_multi(a,pow_mod(b,mod-2,mod),mod));//費馬小定理
    }
}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,030評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,310評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,951評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,796評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,566評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,055評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,303評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,799評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,683評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,899評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,135評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,520評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,757評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,528評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,844評論 2 372

推薦閱讀更多精彩內容