拓展歐幾里得算法
先來看看一個重要的基本定理
裴蜀定理
對於整數a,b,他們關於x,y的線性不定方程\(ax+by=d\),設\(gcd(a,b)=g\),則可證明\(g|d\),換句話說,就是g是a,b的最小線性組合。
證明:
設\(ax+by=d\),\(g=gcd(a,b)\),設\(ax+by\)的最小值為s,
\(\because\) \(g|a,g|b\)
\(\therefore\) \(g|d\),\(g|s\)
設\(q=[\frac{a}{s}].則r= a\mod s=a-q*s=a-q*(ax+by)=a(1-qx)+b(-qy)\)。
可見r也是x,y的線性組合,又r是s的余數,\(r\in [0,s-1]\),又s是最小線性組合,\(\therefore r=0\)。
推出\(s|a\),同理有\(s|b\),則\(s|g\),又已經有\(g|s\),所以\(g=s\)。可知g是ax+by的最小線性組合。
推論:
a和b互質的充要條件是存在x,y使\(ax+by=1\),因為由上面的證明結論知道d(這里是1)一定是gcd(a,b)的倍數。
其實還可以推廣到一堆數互質(這些數的gcd為1)的情況。
拓展歐幾里得
我們知道,一般的 歐幾里得算法是來求兩個數的最大公因數的,但是拓展歐幾里得可以走得更遠,也就是說,它不僅僅求一個gcd,而是可以求出一些額外的東西。前面的定理說了a,b線性組合最小是\(gcd(a,b)\),我們就可以求出\(ax+by=gcd(a,b)\)對應的x,y出來。
怎么求呢?我們已經知道當歐幾里得算法遞歸到終點時,gcd(a,b)中的b已經是零,也就是說,這個時候\(a*1+b*0=a\),x=1,y=0,我們就可以在這時反推上去求解最終的x,y
現在是遞歸返回過程的某一步,我們已經求得了b和a%b的gcd,還有此時的x1,y1,就是說\(b*x1+a\%b*y1=gcd\),要怎么求a,b的x,y呢?
我們知道\(a\%b=a-[\frac{a}{b}]*b\),\(gcd=b*x1+(a-[\frac{a}{b}]*b)*y1=b*x1+a*y1-[\frac{a}{b}]*y1*b=a*y1+(x1-[\frac{a}{b}]*y1)*b=a*x+b*y\)
可以看出\(x=y1,y=x1-[\frac{a}{b}]*b\).遞歸返回時即可更新掉x,y的值返回即可。
代碼:
int ex_gcd(int a,int b,int& x,int& y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
int ans = ex_gcd(b,a%b,x,y);
int tmp = x;
x = y;
y = tmp-a/b*y;
return ans;
}
拓展歐幾里得求逆元
什么是逆元?\(a*x\equiv{1}\mod m\),這里\(x\)就是a的逆元。逆元有什么用呢?*如果我們要求\(a/b \mod m\)的值,而a,b很大,設b的逆元為x,這個時候注意到\((a/b)*x*b=(a/b)\mod m=a*x\mod m\)巧妙地把出發轉換成了乘法。
為什沒求逆元跟歐幾里得算法聯系起來了呢?根據上面裴蜀定理,我們知道gcd是a,b兩個數線性組合的最小值,其他組合值都是gcd的倍數,當gcd為1時,a,b互質,滿足\(ax+by=1\),移項得\(ax=-by+1\),即\(ax\equiv1\mod b\),此時的x就是逆元。實際上線性不定方程組有無窮多解,這里只求正的最小的逆元。
代碼
int cal(int a,int m)
{
int x,y;
int gcd = ex_gcd(a,m,x,y);
//cout << "a " << a << " m " << m << " x " << x << " y " << y << endl;
if(1%gcd!=0) return -1;
x*=1/gcd;
m = abs(m);
int ans = x%m;
if(ans<=0) ans += m;
return ans;
}
這里1%gcd是看gcd是不是1,前面說了,d(這里是1)應該是gcd的倍數,而且不互質的兩個數沒有逆元。\(x*=1/gcd\)實際上更一般的寫為\(x*=d/gcd\),也就是求解一般不定方程\(ax+by=d\)的解,因為d是gcd的倍數,我們就把倍數乘上去解得\(x'=x*(d/gcd)\)。m是負數的話,我們取|m|,如果求出來x是負數,就x%|m|,結果再加上|m|即可。(因為有無窮個解,通解為\(x+m*t\))
參考文章
zhj5chengfeng,擴展歐幾里德算法詳解,https://blog.csdn.net/zhjchengfeng5/article/details/7786595
leader_one,歐幾里得算法/擴展歐幾里得算法,https://blog.csdn.net/leader_one/article/details/75222771
Jollwish,擴展歐幾里得算法,https://wenku.baidu.com/view/a75fdfd376a20029bd642de5.html