數論學習筆記 (4):擴充套件歐幾里得演算法

godmoo發表於2024-05-02

概述

擴充套件歐幾里得演算法 (\(exgcd\)) 可以用來求形如 \(ax+by=c\) 的不定方程的通解。

鋪墊 - \(\small\texttt{ax+by=gcd(a,b)}\)的解

\(exgcd\) 的思想是在用輾轉相除法遞迴 \(gcd(a,b)\)回溯時求出對應方程 \(ax+by=gcd(a,b)\)的解。

考慮方程 \(ax+by=gcd(a,b)\)

看回輾轉相除法的程式碼,我們將他展開一點寫。

void gcd(int a,int b){
	if(!b) return a;
	return gcd(b,a%b);
}

注意最後當 \(b=0\) 時,\(gcd(a,b)=gcd(a,0)=a\),此時當 \(\begin{cases}x=1\\y=0\end{cases}\) 時,\(ax+by=gcd(a,b)\),於是最終狀態下,\(\begin{cases}x=1\\y=0\end{cases}\) 即為其對應方程的解。

接下來,假設我們已經知道了 \(bx+(a\text{ }mod\text{ }b)y=gcd(b,a\text{ }mod\text{ }b)\) 的一組特解 \(\begin{cases}x=x'\\y=y'\end{cases}\),我們嘗試求出 \(ax+by=gcd(a,b)\) 的解。

\(\because ax+by=gcd(a,b)\text{ },\text{ }bx'+(a\text{ }mod\text{ }b)y'=gcd(b,a\text{ }mod\text{ }b)\)

\(\small{且}\text{ }gcd(a,b)=gcd(b,a\text{ }mod\text{ }b)\)

\(\therefore ax+by=bx'+(a\text{ }mod\text{ }b)y'\)

\(\therefore ax+by=bx'+(a-\lfloor\frac{a}{b}\rfloor b)y'\)

\(\small{【變更主元】 得:}\)

\(a(x-y')+b(y-x'+\lfloor\frac{a}{b}\rfloor y')=0\)

\(\small{若想使上式總是成立,只需使:}\)

\(\begin{cases}x-y'=0\\y-x'+\lfloor\frac{a}{b}\rfloor y'=0\end{cases}\)

\(\therefore\begin{cases}x=y'\\y=x'-\lfloor\frac{a}{b}\rfloor y'\end{cases}\)

於是就完成了轉換/轉移,翻譯成程式碼:

// 不需要知道 gcd(a,b) 是多少,無需返回值
void exgcd(int a,int b,int &x,int &y){ // 傳址,直接修改
	if(!b){
		x=1,y=0;
		return;
	}
	exgcd(b,a%b,x,y);
	int tmp=x;
	x=y,y=tmp-(a/b)*y; // 直接修改
}

簡便寫法:

void exgcd(int a,int b,int &x,int &y){
	if(!b){
		x=1,y=0;
		return;
	}
	exgcd(b,a%b,y,x); // 區別:交換x和y的位置,等同於swap(x,y)
	y-=(a/b)*x;
}

擴充套件 - \(\small\texttt{ax+by=c}\)的解

先來看一個定理:

裴蜀定理\(ax+by=c\) 有整數解的充要條件是 \(gcd(a,b) \mid c\)

這個定理是顯然的,至少你從直覺上就覺得它沒問題。

現在我們知道怎麼判無解了,那麼接下來的探究都建立在 \(ax+by=c\) 有界的情況下,那我們開始吧。

\(g=gcd(a,b).\)

\(\therefore g \mid a,g \mid b\)

\(\small{由裴蜀定理:}\)\(g \mid c\)

\(a'=\frac{a}{g},b'=\frac{b}{g},c'=\frac{c}{g}.\)

\(\therefore gcd(a',b')=1\)

發現可以用 \(exgcd\) 求出 \(a'x+b'y=1\) 的解\(\begin{cases}x=x'\\y=y'\end{cases}\)

\(\therefore a'x+b'y=c'\)\(\text{ }\small{的解為}\)\(\begin{cases}x=c'x'\\y=c'y'\end{cases}\)

\(\therefore a'gx+b'gy=c'g\)\(\text{ }\small{即}\text{ }\)\(ax+by=c\)\(\text{ }\small{的解為}\)\(\begin{cases}x=c'x'\\y=c'y'\end{cases}\)

這樣我們就找到了一組特解 \(\begin{cases}x=c'x'\\y=c'y'\end{cases}\).

通解即為 \(\begin{cases}x=c'x'+b'k\\y=c'y'-a'k\end{cases}(k \in \mathbb{Z})\).

(證明、程式碼略)

Tips
C++ 對負數取模的處理與數學中不一樣,如數學中的 \(a\text{ }mod\text{ }b(a \in \mathbb{Z^-})\)C++ 中的值為 \(-(abs(a)\text{ }mod\text{ }b)\).
\(eg:\)
數學:\(-5\text{ }mod\text{ }3=1\)
C++\(-5\text{ }mod\text{ }3=-2\)
為解決這樣的問題,我們一般這麼寫: ans=(a%b+b)%b

相關文章