初等数论之同余总结
上周很颓废的就完成了一个数论的同余专题……总结一下吧,也是备忘。
扩展欧几里德算法
可以求解如Ax+By=C的二元一次不定方程的整数解。
考虑不定方程Ax+By=C,当(A,B)|C时一定有整数解。考虑如何解Ax+By=(A, B)
考虑欧几里德GCD算法GCD(A,B)的最后一步: 当GCD(A, 0)时,(x, y) = (1, 0)为满足Ax+0y=(A, 0)的一组解。考虑倒着推回去: 设 A1x1 + B1y1 = (A1, B1) A2x2 + B2y2 = (A2, B2) = (A1, B1) 由 (A, B) = (B, A % B) (B, A - [A / B] * B) 可得 A1x1 + B1y1 = A2x2 + B2y2 = B1x2 + (A1 - [A1 / B1] * B1)y2 移项得 (x1-y2)A1 + (y1-x2+[A1/B1]y2)B1 = 0 因此 x1 = y2, y1 = x2 - [A1 / B1] * y2 如此递推就可以得到Ax+By=(A, B)的解了
可以得到如下算法:
1 2 3 4 5 6 7 8 9 10 11 12 | |
其中Triple是一个三元组,(x, y, z)分别保存(解x, 解y, GCD)。
在我们解出Ax+By=(A, B)的解后,要求Ax+By=(A, B)的解,只需把(x, y)乘上C/(A, B)即可!
Ax+By=C的x的最小非负整数解
其实二元一次不定方程有一个定理:
若(x0, y0)为一组解,那么(x0+B/(A,B)*t, y0-A/(A,B)*t), t∈Z,也是一组解
由此可以知道,x的最小非负整数解就是把x0不断加减B/(A,B)使得它是最小非负整数解
简单地来说就是:x = x0 % (B / (A,B))
a%b就是:{cpp}(a % b + b) % b{/cpp}
乘法逆元
大家都知道a / b = a * b^(-1),大家也都知道在模上不能直接计算除法。因此模上的除法一般转换为乘上其乘法逆元。
所谓a在模p下的乘法逆元x也就是:ax ≡ 1(mod p)
很简单,设ax = py + 1,扩展欧几里德套上解之
注意,这里有解的条件,(a, p)|1,也就是(a, p) = 1。因此,乘法逆元不一定存在。
线性模方程组
考虑如下方程组:
A1x ≡ B1(mod M1) A2x ≡ B2(mod M2) A3x ≡ B3(mod M3) ... Anx ≡ Bn(mod Mn)
先把系数A除掉(乘上乘法逆元),变成如下形式:
x ≡ C1(mod M1) x ≡ C2(mod M2) x ≡ C3(mod M3) ... x ≡ Cn(mod Mn)
求解的方法是两两合并:
先考虑 x ≡ C1(mod M1) x ≡ C2(mod M2) 设x = M1y + C1 = M2z + C2 即M1y + M2z = C2 - C1 扩展欧几里德套上解之,得(y, z) 那么x = M1y + C1 此时两个方程合并为: x ≡ M1y + C1(mod LCM(M1, M2)) 再与 x ≡ C3(mod M3) 合并,如此反复,最后的得到我们要的解: x ≡ C(mod M)
其中只要任意一步(y, z)无解,方程组无解。
程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
中国剩余定理
如果方程组:
x ≡ C1(mod M1) x ≡ C2(mod M2) x ≡ C3(mod M3) ... x ≡ Cn(mod Mn)
满足Mi两两互质,可以使用中国剩余定理来解决。
中国剩余定理的核心思想是对于每一个模方程求出一个Ei,符合:Ei ≡ 0(mod Mj) j != i 以及 Ei ≡ 1(mod Mj) j == i
如此一来,x ≡ Sigma(EiCi)(mod M)就是方程组的解了
下面看如何求解Ei:
令 M = M1*M2*...*Mn mi = M/Mi 因为Ei满足: Ei ≡ 0(mod mi) Ei ≡ 1(mod Mi)
扩展欧几里德套上解之即可得到Ei
注意这里必定有解
因为,设Ei = mi*y又设Ei = Mi*z+1,那么mi*y - Mi*z = 1
由于(mi, Mi) = 1,因此必定有解
1 2 3 4 5 6 7 | |
模上除法
计算A/B%M,如果有逆元,乘上逆元就好了。没有的话比较麻烦:
把M拆成P1^C1 + P2^C2 + ... + Pk^Ck的形式,分别计算A / B % (Pi^Ci)的结果,再合并方程组
由于B在Pi^Ci仍然不一定存在逆元,所以我们把A和B都拆成如下形式:Pi^m * n
这样一来A/B%Pi变成了:(Pi^m * r) / (Pi^n * s) % Pi
显然,m < n时等于0,否则就变成了:(Pi^(m-n) * r) / s % Pi
此时有(s, Pi) = 1,因此乘上s的逆元就好了
到最后把方程组合并就好了
阶乘取模分解
n! % P假设模P的是素数(不是的话分解质因数拆掉,分别处理,再中国剩余定理合并),还是得把n!转换成P^a * b的形式
令
k = [n/p]
m = n%p
n! mod p = 1 * 2 * ... * (p-1) * p
* (p+1) * (p+2) * ... * (2p-1) * 2p
* ...
* (kp+1) * (kp+2) * ... * (kp+m) mod p
= 1 * 2 * ... * (p-1) * p
* 1 * 2 * ... * (p-1) * 2p
* ...
* 1 * 2 * ... * m mod p
= [(n%p)! * (p-1)!^(n/p)] * [(n/p)! * p^(n/p)] mod p
其中(n%p)!和(p-1)!都可以预处理,(p-1)!^(n/p)和p^(n/p)都可以快速幂,剩下的只需要递归处理(n/p)!即可
可以参考[BZOJ2313]分组,以及[BZOJ2142]礼物。
组合数取模
C(n, k) % p仍然假设p为质数。这时候就有神奇的Lucas定理:
C(n, k) % p = Lucas(n, k, p) = Lucas(n/p, k/p, p) * C(n%p, k%p)
原理就是阶乘取模
另外注意费马小定理:
p为质数那么,a^(p-1) ≡ 1(mod p)
也就是说a^(p-2)在mod p下为a的乘法逆元!如此一来,配合快速幂,计算C(n%p, k%p)就非常快了,p的范围能上10^4
程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
欧拉函数
- [Euler’s totient function](http://en.wikipedia.org/wiki/Euler’s_totient_function)
- 线性时间内筛素数和欧拉函数
phi(x)或者φ(x),表示1~x中和x互质的有多少个数。定义/性质如下:
phi(x) = n * product{p|n & p is prime, 1 - 1/p}phi(p^k) = (p-1) * p^(k-1)phi(n^m) = phi(n) * n^(m-1)phi(mn) = phi(m) * phi(n),(gcd(m, n) = 1)phi(mn) = phi(m) * phi(n) * gcd(m, n)/phi(gcd(m, n))n = sum{d|n, phi(d)}- 若
gcd(a, p) = 1,则a^phi(p) ≡ 1(mod p)
阶
若a^n ≡ 1 (mod p),那么称最小的符合要求的那个n为a关于mod p的阶。因为a^phi(p) ≡ 1 (mod p),所以n一定是phi(p)的约数。算的时候就是从小到大枚举phi(p)约数然后快速幂验证。
1 2 3 4 5 6 7 8 9 10 | |
原根
如果g的阶是phi(p)的话,那么称g是原根。只有**1、2、4、奇质数的幂、2*奇质数的幂**才有原根。因为原根都很小,所以一般就暴力枚举了。
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
指标(离散对数)
若(b, p) = 1, 0 <= a < phi(p),满足g^a ≡ b (mod p),那么a称为b关于p的指标,记为ind(g)b,简写为ind b。有下列性质:
a ≡ b (mod p)<=>ind a ≡ ind b (mod phi(p))ind (a*b) ≡ ind a + ind b (mod phi(p))ind (a^n) ≡ n ind a (mod phi(p))
很明显,指标要用BSGS求了,因为p是质数,所以BSGS还是非常好写的。参考:Baby Step Giant Step 及其扩展算法