擴展歐幾里得算法是用來在已知一組 \((a,b)\) 的時,求解一組 \((x,y)\) 使得ios
根據相關的知識能夠獲得算法
由當 \(b=0\) 是便可得出 \(x=1,y=0\)ui
便可遞推求解spa
如何來作?code
進而能夠得出結論get
有告終論就能夠實現簡單的求解string
int exgcd(int a,int b) { if(!b) { x=1; y=0; return a; } int gcd=exgcd(b,a%b); int tmp=x; x=y; y=tmp-a/b*y; return gcd; }
爲何要用?it
在當前個人理解範圍內,它既能夠求出最大公約數,而且求出來的 \(x,y\) 能夠進行解決一些問題io
可用於進行對二元一次不定方程的求解class
即
根據裴蜀定理可得,這個方程有整數解的充要條件爲
一樣,該方程能夠等同於
P5656 板子能夠爲較爲拓展的應用
一、如何來求 \(ax+by=c\) 的一個解
首先咱們在有整數解的狀況下求出
的解 \((x_0,y_0)\)
由\(k=\frac{c}{gcd(a,b)}\)
得出來
該方程的一個解能夠爲
\(\begin{cases} x=kx_0\\y=ky_0 \end{cases}\)
也就是方程在同除完 \(k\) 後求出解來,進而乘上 \(k\) 得出當前的解,由於\(a,b\)是不變的
二、如何根據一組解求出多組解來
首先任意選擇一個數\(t\),爲了方便敘述和計算,通常設\(t=1\)
設兩個整數 \(m,n\)
咱們能夠得出
由
可知
那麼就是尋找一組 \((m,n)\)使得該方程 成當即可
能夠獲得
\(\begin{cases} m=\frac{b}{gcd(a,b)}\\n=-\frac{a}{gcd(a,b)} \end{cases}\)
代進去等式成立,進而就能夠獲得一組解
\(\begin{cases} x_i=x+m\\y_i=y+n \end{cases}\)
三、考慮正整數解的最大值最小值,及其正整數解的個數
首先設置一下變量
\(\begin{cases} d=gcd(a,b)\\tx=\frac{b}{d} \\ty=\frac{a}{d} \end{cases}\)
首先那咱們從x的最小值開始找起
能夠獲得式子
獲得\(x_{min}=x+\lceil\frac{1-x}{tx}\rceil\times tx\)
那麼此時一樣能夠獲得 \(y_{max}=y-\lceil\frac{1-x}{tx}\rceil\times ty\)
那麼就在求一下
那麼 \(y\) 的最小正整數解即爲 \(y_{max}+\lceil\frac{1-y_{max}}{ty}\rceil\times ty\)
一樣適用於有正整數解狀況下的\(y_{min}\)
能夠很顯然的發現\(y_{min}=y_{max}\bmod ty\)
利用狀況一中的結論能夠求出
至於解的個數能夠參考在\(y_{max}\to y_{min}\)過程當中 $ k $的變化
正整數解的組數即爲 \(\lfloor\frac{y_{max}-1}{ty}\rfloor+1\)
代碼請參考P5656
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #include<stack> #define int long long using namespace std; int x,y;//用於求解 int read()//不到卡常不用快讀=_= { char c=getchar(); int f=1; int x=0; while(c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); } while(c>='0'&&c<='9') { x=(x<<1)+(x<<3)+(c^'0'); c=getchar(); } return x*f; } int exgcd(int a,int b) { if(!b) { x=1; y=0; return a; } int ans=exgcd(b,a%b); int tmp=x; x=y; y=tmp-a/b*y; return ans; } signed main() { int t; t=read(); while(t--) { int a,b,c; a=read(); b=read(); c=read(); int d=exgcd(a,b); if(c%d!=0)//根據裴蜀定理得出,c不是gcd(a,b)的倍數,則必定無整數解 { cout<<-1<<endl; continue; } x=x*c/d; y=y*c/d;//求出一組正整數解 int tx=b/d; int ty=a/d; int k=ceil((1.0-x)/tx);//求出x_min正整數;判\斷y是否爲正整數 x+=k*tx;//x_min y-=k*ty;//求出此時的ymax if(y<=0) { int ymin=y+ty*ceil((1.0-y)/ty)*1ll; printf("%lld %lld\n",x,ymin); } else { printf("%lld ",(y-1)/ty+1);//個數 printf("%lld ",x);//最小值 printf("%lld ",(y-1)%ty+1);//最小值 printf("%lld ",x+((y-1)/ty*tx));//max printf("%lld \n",y);//max } continue; } return 0; }