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 就是求解这个方程的算法:
首先有 (amod b = a - blfloor dfrac ab floor), 其次由于 (gcd(a,b) = gcd(b,amod b)), 那么如果求出 (sf y'b +x'(amod b) = gcd(a,b)) 的解, 就有: (sf y'b +x'(amod b) = y'b +x'(a-blfloor dfrac ab floor) = (y'- x'lfloor dfrac ab floor)b + x'a) , 这就是 (ax+by=gcd(a,b)) 的一个解。
注意这个解一定不是唯一的, 如果求出了一组解 (sf (x_0、y_0)) 那么 ((x_0+kdfrac{b}{gcd(a,b)}, y_0-kdfrac{a}{gcd(a,b)}), quad kinBbb 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}^nlfloor dfrac{Ai+B}{C} floor) 。
待补待补。
我得先读一下具体数学第三章再学这个算法。
明年不退役的话再说吧。