exgcd 学习笔记
定義
又名擴展歐幾里得算法(輾轉相除法)
是用來求 \(ax+by=gcd(a,b)\) 中未知數的算法
算法證明
拿到一組 \(a,b\) ,設 \(G=gcd(a,b)\)
目標:求出滿足 \(ax+by=G(1)\) 的 \(x\) 與 \(y\)
如果 已知一組 \(x2,y2\) ,滿足 \(bx2+\) \((a\) \(mod\) \(b)y2=G(2)\)
此時結合 \((1)(2)\) 得
\(ax+by=\) \(bx2+\) \((a\) \(mod\) \(b)y2(3)\)
那么當 如果 滿足時,目標就成了求滿足 \((3)\) 的 \(x,y\),其中 \(a,b,x2,y2\) 均已知
根據取模運算是 \(a\) \(mod\) \(b=a-b*(a/b)\)
所以方程 \((3)\) 實則是
\(ax+by=\) \(bx2+\) \((a-b*(a/b))y2\)
\(->\) \(ax+by=bx2+ay2-b*(a/b)y2\)
\(->\) \(ax+by=ay2+b(x2-(a/b)y2)\)
那么在根據方程 \(ax+by=G(1)\) 得出一組必然的解:
\(x=y2,y=x2-(a/b)y2(4)\)
可見只需求出 \(x2,y2\) ,就能求出正確的 \(x,y\),問題就轉化成了求 \(x2,y2\)
將方程 \((1)\) 與 \((2)\) 對比一下:
\(ax+by=G(1)\)
\(bx2+\) \((a\) \(mod\) \(b)y2=G(2)\)
發現原方程的 \(a\) 變成了 \(b\),原方程的 \(b\) 變成了 \(a\) 而已
所以新的方程也可以看做 \(ax+by=G\) 的形式,然后按照上面的程序進行下來,發現問題又變為求 \(x3,y3\) 再求 \(x4,y4\) \(......\) 即一個遞歸的過程
遞歸過程中 \(a,b\) 不斷被替換為 \(b,a\) \(mod\) \(b\),這個過程和普通的歐幾里得是一樣的,所以最后會出現 \(a(n)=G,b(n)=0\)
那么這特就是最后一層,此時就要直接返回了,需要一組 \(x(n),y(n)\) 滿足 \(a(n)x(n)+b(n)y(n)=G(5)\),然而 \(a(n)=G,b(n)=0\),所以只要 \((5)\) 的 \(x(n)\) 取 \(1\) 就必定滿足了,\(y(n)\) 就隨便取個 \(0\) 就行了
最后一層結束后,就開始返回,知道最上一層,每一層都可以通過下一層的 \(x(k+1),y(k+1)\) 求出當前層的 \(x(k),y(k)\)
整個過程就是:以輾轉相除的方式向下遞進,不斷縮小系數,保證會出現有確定解的最后一層
例題
題目鏈接 同余方程
問題處理
題目問的是滿足 \(ax\) \(mod\) \(b=1\) 的最小正整數(a,b均為正整數)
問題可以轉化成求 \(ax+by=1\) 中 \(x\) 的值,其中 \(y\) 是個引入的輔助數(y一定是一個負數,但是寫成 \(+\) 的形式以便 \(exgcd\) 算法)
問題仍需轉化,\(exgcd\) 求得是 \(ax+by=gcd(a,b)\),所以求方程 \(ax+by=m\) 必須滿足的條件就是 \(m\) \(mod\) \(gcd(a,b)=0\)
簡單證明一下:
由最大公因數的定義,\(a,b\) 均是 \(gcd(a,b)\) 的倍數,因為 \(m=ax+by\),所以 \(m\) 一定是 \(gcd(a,b)\) 的倍數,即 \(m\) \(mod\) \(gcd(a,b)=0\)
可得這道題中,必須滿足 \(1\) \(mod\) \(gcd(a,b)=0\),那么 \(gcd(a,b)\) 就必須等于 \(1\) 了,即 \(a,b\) 互質(數據一定是滿足的)
之后通過上述的 \(exgcd\) 算法即可,但是題目要求 \(x\) 的最小值,僅僅 \(exgcd\) 無法滿足,所以需要答案處理
答案處理
求出來的 \(x,y\) 僅僅滿足 \(ax+by=1\),而 \(x\) 不一定是最小正整數解。有可能太大,也可能是負數
解決方案是:\(x\) 批量地減去或加上 \(b\),能保證 \(ax+by=1\),因為:
\(ax+by=1\)
\(->\) \(ax+by+k*ba-k*ba=1\)
\(->\) \(a(x+kb)+(y-ka)b=1\)
1.顯然這并不會把方程中的任何整數變為非整數
2.加上或減去 \(b\) 不會使 \(x\) 錯過任何解,可以這么理解:
已經求出一組 \(x,y\) 使得 \(ax+by=1\),也就是 \((1-ax)/b=y\),\(y\) 是整數,可見目前 \(1-ax\) 是 \(b\) 的倍數
現在給 \(x\) 加上 \(kb\)(k為整數),則變為:
\((1-a(x+kb))/b\)
\(=(1-ax)/b+ak\)
仍滿足其為 \(b\) 的倍數,由此當 \(x\) 的變化量為 \(b\) 的倍數時,等式仍滿足
因此到最后,如果 \(x\) 太小就不斷 \(+b\) 直到 \(>=0\),反之則一直減直到最小正整數值,就是這么寫
x=(x%b+b)%b;
總代碼如下
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=1;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
int a,b,x,y;
int exgcd(int a,int b,int &x,int &y)
{
if(b==0) {x=1;y=0;return a;}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
read(a),read(b);
exgcd(a,b,x,y);
x=(x%b+b)%b;
cout<<x;
}
總結
以上是生活随笔為你收集整理的exgcd 学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: keystone和beaengine的编
- 下一篇: Foundation框架