1. 程式人生 > >【learning】 擴展歐幾裏得算法(擴展gcd)什麽的

【learning】 擴展歐幾裏得算法(擴展gcd)什麽的

code 條件 逆元 一次 一個 div 質數 我們 text

有這樣的問題:

給你兩個整數數$(a,b)$,問你整數$x$和$y$分別取多少時,有$ax+by=gcd(x,y)$,其中$gcd(x,y)$表示$x$和$y$的最大公約數。

數據範圍$a,b≤10^{18}$。

求解這個問題有一種方法,叫做擴展歐幾裏得算法(簡稱擴歐),其本質是一個遞歸求解的過程。

首先由一個前置的結論是$gcd(x,y)=gcd(y,x\%y)$。此處的$\%$為$c++$中取模操作,下同。

我們不妨設$a>b$

當$a≠0,b=0$時,則顯然有$x=1,y=0$。此時$gcd(a,b)=a$。

當$b≠0$時,我們假設我們已經求出了$bx‘+(b\%a)y‘=gcd(a,b)$的$x‘$和$y‘$(這是式1),我們現在要求的是$ax+by=gcd(a,b)$。

我們對式子$1$做一些微小的變式

原式$=bx‘+(b\%a)y‘$

$=bx‘+(a-\lfloor \frac{a}{b} \rfloor \times b)\times y‘$

$=bx‘+ay‘-\lfloor \frac{a}{b} \rfloor \times b\times y‘$

$=ay‘+b(x‘-\lfloor \frac{a}{b}\rfloor y‘)$

不難發現,$x=y‘$,$y=(x‘-\lfloor \frac{a}{b}\rfloor y‘)$就是一組符合條件的解。

然後無腦遞歸解決即可,代碼很短,復雜度顯然是$O(\log_2 a)$的。

1
void exgcd(int a,int b,int &x,int &y){ 2 if(!b) {x=1; y=0; return;} 3 exgcd(b,a%b,y,x); 4 y-=a/b*x; 5 }

下面來說下這東西能幹啥

我們不難發現,我們需要求$a$在模$b$意義下的乘法逆元(前提條件,$a$與$b$互質)

我們可以執行一次$exgcd(a,b,x,y)$,然後$x$就是$a$在模$b$意義下的逆元。

證明顯然:

$ax+by=1$

$ax\equiv 1(\mod b)$

當模數不是質數的時候你就會知道這東西有多重要。

【learning】 擴展歐幾裏得算法(擴展gcd)什麽的