简单公约数算法
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\) 。
待补待补。
我得先读一下具体数学第三章再学这个算法。
明年不退役的话再说吧。