標籤:span div 簡單 int $$ The ica exgcd 約數
0、歐幾裡德定理
一切的基礎,自然就是歐幾裡德定理了。它的形式非常簡單(sometimes naive)
gcd(a,b)=gcd(b,a mod b)
證明:
假設a,b的公約數為g,且$${a}={bx+y}{(x,y\in Z)}$$
則顯然有$${g \mid a},\qquad {g \mid b},\qquad{{a}\ mod\ {b}}={y}$$
$${\because g \mid b}$$
$${\therefore g \mid bx}$$
又$${\because g \mid a}$$
$${\therefore g \mid {(a-bx)}}$$
即$${g \mid y}$$
即$${g \mid {{a}\ mod\ {b}}}$$
故g是b和a mod b的公約數
即(a,b)和(b,a mod b)的公約數是相同的,所以它們的最大公約數也是相同的。
- 歐幾裡德演算法
又名"輾轉相除法",是目前求最大公約數的通用演算法,實現簡易功能強大。(代碼可以說是很漂亮了)
原理正是歐幾裡德定理,話不多說上代碼:
int gcd(int x, int y){return y ? gcd(y, x%y) : x;}
時間複雜度:由於a mod b必然小於,上一次的b變成a,上一次的a mod b變成b,故最差情況也是O(log n)的。
- Bezout定理
在介紹擴充歐幾裡德定理之前,首先需要介紹一下Bezout定理(貝祖定理,裴蜀定理)。
Bezout定理:若${ax+by=z}$,則有$${gcd(a,b)}\mid{z}$$
Bezout定理拓展:若${a_1x_1+a_2x_2+...+a_nx_n}=z$,則有$${gcd(a_1,a_2,...,a_n)}\mid{z}$$
- 擴充歐幾裡德演算法
擴充歐幾裡德演算法十分強大,可以用來求二元一次方程的通解。
顯然當 $b=0$,$gcd(a,b)=a$。此時 $x=1,y=0$
當$a>b>0$ 時
設 $$ax_1+by_1=gcd(a,b)$$
$${bx_2}+{({a}\ mod\ {b})y_2}={gcd(b,{a}\ mod\ {b})}$$
由歐幾裡德定理得 $$gcd(a,b)=gcd(b,{{a}\ mod\ {b}})$$
則:$$ax_1+by_1=bx_2+{({a}\ mod\ {b})y_2}$$
也就是 $$ax_1+by_1=ay_2+b(x_2-{[{a}/{b}]}{\times} y_2)$$
根據恒等定理得:$${x_1=y_2},\qquad{y_1=x_2-{[{a}/{b}]}{\times} y_2}$$
這樣我們就得到了求解${x_1},{y_1}$的方法:${x_1},{y_1}$的值基於 ${x_2},{y_2}$
由Bezout定理我們知道:${ax+by=z}$,z為gcd(a,b)若干倍,所以我們先求解${ax+by={gcd(a,b)}}$,再將求出的解乘以 ${{z}/{gcd(a,b)}}$ 就好了。(上文中‘/‘指整除)
Cpp代碼:
int exgcd(int a, int b, int x, int y) { int d = a; if (b != 0) { d = exgcd(b, a%b, y, x); y -= (a / b)*x; } else { x = 1; y = 0; } return d;}
擴充歐幾裡德演算法