E·M·T
定義 \(gcd(a,b)\) 為整數 \(a、b\) 的最大公約數。
首先是一些瑣碎的性質:
-
對於兩個數 \(p_1^{a_1}p_2^{a_2}\cdots p_k^{a_k}、p_1^{b_1}p_2^{b_2}\cdots p_k^{b_k}\) 來說, \(gcd(p_1^{a_1}p_2^{a_2}\cdots p_k^{a_k},p_1^{b_1}p_2^{b_2}\cdots p_k^{b_k}) = p_1^{min(a_1,b_1)}p_2^{min(a_2,b_2)}\cdots p_k^{min(a_k,b_k)}\) , \(lcm\) 的話類似, 只是 \(min\) 改成了 \(max\)。
-
\(gcd(a,b)=1 \Rightarrow gcd(a,bc)=gcd(a,c)\) 對着上面的那條性質很好理解。
-
\(gcd(a,b) = gcd(a-b,b)\) , 這個是歐幾里得算法的基礎; \(gcd(a,n) = gcd(a+n,n)\) ,這是分號左邊那條的推論, 它說明了 \(gcd_n(x) = gcd(n,x)\) 這個函數是周期性的。
-
\(gcd(\dfrac{a}{gcd(a,b)}, \dfrac{b}{gcd(a,b)}) = 1\), 結合第一條很好理解。
總之結合第一條都很好證, 因為第一條基本包含了 \(gcd\) 函數的全部信息。
exgcd
首先有個叫Bezout定理的, 意思是 \(ax+by=gcd(a,b)\) 必定有解, 其中 \(a、b\) 是給定的常數而 \(x、y\) 是變量。(不會證)
exgcd 就是求解這個方程的算法:
首先有 \(a\mod b = a - b\lfloor \dfrac ab \rfloor\), 其次由於 \(gcd(a,b) = gcd(b,a\mod b)\), 那么如果求出 \(\sf y'b +x'(a\mod b) = gcd(a,b)\) 的解, 就有: \(\sf y'b +x'(a\mod b) = y'b +x'(a-b\lfloor \dfrac ab \rfloor) = (y'- x'\lfloor \dfrac ab \rfloor)b + x'a\) , 這就是 \(ax+by=gcd(a,b)\) 的一個解。
注意這個解一定不是唯一的, 如果求出了一組解 \(\sf (x_0、y_0)\) 那么 \((x_0+k\dfrac{b}{gcd(a,b)}, y_0-k\dfrac{a}{gcd(a,b)}), \quad k\in\Bbb Z\) 就是通解, 通解是無限的, 要得到最小正整數解就直接隨便求出一個 \(x_0\) 然后膜上 \(\dfrac{b}{gcd(a,b)}\) 搞成最小正整數就行了。
代碼的話可以這樣寫:
void exgcd(int a,int b,int &x,int &y,int &GCD) {//由於exgcd的算法過程與gcd有重疊, 所以為了方便可以順便求 a、b的 GCD
!b ? x=1,y=0,GCD=a : (exgcd(b,a%b,y,x,GCD), y-=x*(a/b));
}
要是不想壓行可以這樣寫,:
void exgcd(int a,int b,int &x,int &y,int &GCD) {
if(b==0) {GCD=a; x=1; y=0; return; }
exgcd(b, a%b, y, x, GCD);
y -= x*(a/b);
}
個人覺得壓行更利於查錯, 雖然這種算法不應該出錯。
類歐
最基本的模型: \(\sf sol(n,A,B,C) = \sum_{i=1}^n\lfloor \dfrac{Ai+B}{C}\rfloor\) 。
待補待補。
我得先讀一下具體數學第三章再學這個算法。
明年不退役的話再說吧。