gcd以及exgcd入門講解

gcd就是最大公約數,gcd(x, y)通常用(x, y)表示。與此相對的是lcm,最小公倍數,lcm(x, y)通常用[x, y]表示。spa

 

人人都知道:lcm(x, y) = x * y / gcd(x, y)code

 

證實起來也不是很難:blog

(這真的是我本身寫的,由於博客園不支持這格式……)遞歸

 

至於gcd的求法,想必各位在高中都學過展轉相除法和更相減損之術,這裏只講展轉相除法(更相減損之術略慢)博客

 

首先不妨設 x ≤ y,則gcd(x, y)  =gcd(x, x +y) = gcd(x, y - x).因此gcd(x, y) = gcd(y % x, x),所以能夠遞歸求解。class

複雜度證實:由於y % x ≤ x && x ≤ y,因此y % x < y / 2。所以在最壞狀況下爲O(nlogn)。(用斐波那契數列的相鄰兩個數能夠達到最壞複雜度)擴展

 

那麼接下來說一下擴展gcd。gc

exgcd能夠用來判斷並求解形如ax +by = c 的方程,當且僅當gcd(a, b) | c時,存在整數解x, y。im

也就是說,exgcd能夠用來求解方程ax +by = gcd(a, b)d3

令a = b, b = a % b,則有方程b *x1 +(a % b) * y1 = gcd(b, a % b)

又由於gcd(a, b) = gcd(a % b),且a % b = a - b * ⌊a / b⌋

則b * x1 + (a - b * ⌊a / b⌋) * y1  =gcd(a, b)

整理得:a * y1 +b * (x1 - ⌊a / b⌋ *y1) = gcd(a, b)

因此原方程中:x = y1, y = x1 - ⌊a / b⌋ *y1。因而咱們只要遞歸求出x1, y1就能求出x, y。

代碼很短

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

其中c = gcd(a, b)

值得注意的是,遞歸調用的時候y的位置上傳了x,x位置上是y,也就是說,y裏存的是x1,x裏存的是y1,因此y -= a / b *y1,即y -= a / b * x。

 

咱們如今已經求得了ax +by = gcd(a, b)的解,那麼對於方程ax + by = c (gcd(a, b) | c)呢?

由於已經知道a *x1 +b * y1 = gcd(a, b)的解x1, y1,左右兩邊同乘以c / gcd(a, b) 得:

a * x1 * c / gcd(a, b) +b * y1 * c / gcd(a, b) = c

則原方程的一組解x2 = x1 * c / gcd(a, b), y2 = y1 * c / gcd(a, b)

由此得出解集{(x, y) | x = x2 + k * b / gcd(a, b), y = y2 - k * a / gcd(a, b), k ∈ z}

相關文章
相關標籤/搜索