二元一次不定方程(Exgcd)(更方便的解法)

XP3301_Pipi發表於2024-07-22

擴充套件歐幾里得演算法(Exgcd)

裴蜀定理

對於任意一組整數 \(a,b\),存在一組整數 \(x,y\),滿足 \(ax+by=\gcd(a,b)\)

Proof:

考慮數學歸納法。

\(b=0\) 時,由於 \(\gcd(a,0)=a\),則對於 \(ax+0y=a\) 這個不定方程,\(x=1\)\(y\) 取任意整數。

假設存在一組整數 \(x,y\),滿足 $bx+(a\bmod b)y=\gcd(b,a\bmod b)=\gcd(a,b) $。

那麼接下來證明也存在一組整數 \(x',y'\) 滿足 \(ax'+by'=\gcd(a,b)\)

\[\begin{aligned} bx+(a\bmod b)y &= bx+(a-b\lfloor\dfrac{a}{b}\rfloor)y\\ &= bx+ay-b\lfloor\dfrac{a}{b}\rfloor y\\ &= ay+b(x-\lfloor\dfrac{a}{b}\rfloor y) \end{aligned} \]

\(x'=y,y'=x-\lfloor\dfrac{a}{b}\rfloor y\) 時滿足條件。

那麼利用輾轉相除法進行遞迴,總能遞迴到 \(b=0\) 的情況。命題得證。

Exgcd

求關於 \(x,y\) 的方程 \(ax+by=c\) 的整數解。

\(d=\gcd(a,b)\),方程有整數解的充要條件是 \(d\mid c\)

Proof:

\(a=k_1d,b=k_2d\),則有 \(k_1dx+k_2dy=c \Rightarrow k_1x+k_2y=\dfrac{c}{d}\)

先證必要性: 由於 \(\dfrac{c}{d}\) 必須為整數,則 \(d \mid c\)

再證充分性:上式中,\(k_1\perp k_2\),則方程 \(k_1x'+k_2y'=1\) 一定有整數解。由於 \(\dfrac{c}{d} \in\mathbb{Z}\),那麼原方程也一定有整數解。

先將方程化簡,兩邊同除以 \(d\)。此時 \(a,b\) 互質。

為了方便表述,下面提到的方程都是化簡後的方程。

那麼我們可以先利用裴蜀定理求出 \(ax'+by'=1\) 的一組特解 \(x',y'\),從而求出原方程的一組特解 \(x_0=cx’,y_0=cy'\)

考慮如何求出通解。

\(x\) 加上一個數,那麼 \(y\) 就要減去一個數。設這兩個數為 \(\Delta_x,\Delta_y\),則有:

\[\begin{aligned} a(x+\Delta_x)+b(y-\Delta_y) &= c\\ ax+a\Delta_x+by-b\Delta_y &= c\\ a\Delta_x-b\Delta_y&=0\\ a\Delta_x &= b\Delta_y \\ \dfrac{a}{b} &= \dfrac{\Delta_y}{\Delta_x} \end{aligned} \]

由於 \(a,b\) 互質,則 \(\dfrac{a}{b}\) 為最簡整數比,則有 \(a \mid \Delta_y\)\(\ b\mid \Delta_x\)

由於 \(\Delta_x,\Delta_y \in \mathbb{Z}\),則 \(\Delta_x\) 最小取到 \(b\)\(\Delta_y\) 最小取到 \(a\)

通解即為:

\[\begin{cases} x=x_0+kb\\ y=y_0+ka\\ \end{cases} (k\in \mathbb{Z}) \]

代回原方程,可以消掉 \(kb,ka\)

接下來考慮,當存在正整數解時,如何求出最小正整數解與正整數解的個數。

\(x\) 的通解進行變形,求 \(x\) 的最小正整數解 \(x_1\)

\[\begin{aligned} x_1 \bmod b &= (x_0+kb) \bmod b\\ x_1 \bmod b &= x_0 \bmod b\\ x_1&=(((x_0-1) \bmod b)+b)\bmod b+1 \end{aligned} \]

先減一是為了避免 $x_0 \bmod a $ 一開始就為 \(0\) 的情況,從而保證 \(x_1>0\)

易得,當 \(x\) 增大時,\(y\) 減小。當 \(x\)\(x_1\) 時,\(y\) 取到最大正整數解 \(y_2\)

同理,求出 \(y\) 的最小正整數解 \(y_1\),當 \(y\)\(y_1\) 時,\(x\) 取到最大正整數解 \(x_2\)

由通解公式可得,\(x\) 每兩個整數解之間相差 \(b\)\(y\) 每兩個整數解之間相差 \(a\)

正整數解的個數即為 \(\dfrac{x_2-x_1}{b}+1\)\(\dfrac{y_2-y_1}{a}+1\)

Ex.1 【模板】二元一次不定方程 (exgcd)

根據上面的分析,套用公式即可。

ll T,A,B,C,x,y,d,x1,x2,y1,y2,cnt; 

ll GetX(ll Y){return (C-B*Y)/A;}

ll GetY(ll X){return (C-A*X)/B;}

ll Exgcd(ll a,ll b,ll &x,ll &y){
	if(b==0) return x=1,y=0,a;
	ll res=Exgcd(b,a%b,x,y);
	ll z=x;
	x=y;
	y=z-(a/b)*y;
	return res;
}

void Solve(){
	read(A),read(B),read(C);
	d=Exgcd(A,B,x,y);
	if(C%d) return puts("-1"),void();
	A/=d,B/=d,C/=d;
	x*=C,y*=C;
	x1=((x-1)%B+B)%B+1;
	y2=GetY(x1);
	y1=((y-1)%A+A)%A+1;
	x2=GetX(y1);
	cnt=(x2-x1)/B+1;
	if(y2<=0) printf("%lld %lld\n",x1,y1);
	else printf("%lld %lld %lld %lld %lld\n",cnt,x1,y1,x2,y2);
}

Ex.2 [NOIP2012 提高組] 同餘方程

對式子進行變形:

\[\begin{aligned} ax &\equiv 1 \pmod{b}\\ ax+by &= 1 \end{aligned} \]

利用 Exgcd 求解即可。

這是非常常用的變形技巧,也是當 \(a,b\) 互質但 \(b\) 不是質數時求逆元的方法。

Ex.3 青蛙的約會

設跳躍 \(k\) 次後兩青蛙相遇,則可列出方程:

\[\begin{aligned} x+kn &\equiv y+km &\pmod{L}\\ (x-y)+k(n-m) &\equiv 0 &\pmod{L}\\ (x-y)+k(n-m) &= pL\\ k(n-m)-pL&=y-x\\ kS-pL&=C \end{aligned} \]

其中 \(S,L,C\) 為常數。

\(k,p\) 看作未知數,利用 Exgcd 求 \(k\) 的最小正整數解即可。

相關文章