Lucas 定理
Lucas 定理用于求解大组合数取模的问题,其中模数必须为素数。正常的组合数运算可以通过递推公式求解(详见排列组合),但当问题规模很大,而模数是一个不大的质数的时候,就不能简单地通过递推求解来得到答案,需要用到 Lucas 定理。
求解方式
Lucas 定理内容如下:对于质数 p p p,有
( n m ) m o d p = ( ⌊ n / p ⌋ ⌊ m / p ⌋ ) ⋅ ( n m o d p m m o d p ) m o d p \binom{n}{m}\bmod p = \binom{\left\lfloor n/p \right\rfloor}{\left\lfloor m/p\right\rfloor}\cdot\binom{n\bmod p}{m\bmod p}\bmod p (mn)modp=(⌊m/p⌋⌊n/p⌋)⋅(mmodpnmodp)modp
观察上述表达式,可知 n m o d p n\bmod p nmodp 和 m m o d p m\bmod p mmodp 一定是小于 p p p 的数,可以直接求解, ( ⌊ n / p ⌋ ⌊ m / p ⌋ ) \displaystyle\binom{\left\lfloor n/p \right\rfloor}{\left\lfloor m/p\right\rfloor} (⌊m/p⌋⌊n/p⌋) 可以继续用 Lucas 定理求解。这也就要求 p p p 的范围不能够太大,一般在 1 0 5 10^5 105 左右。边界条件:当 m = 0 m=0 m=0 的时候,返回 1 1 1。
时间复杂度为 O ( f ( p ) + g ( n ) log n ) O(f(p) + g(n)\log n) O(f(p)+g(n)logn),其中 f ( n ) f(n) f(n) 为预处理组合数的复杂度, g ( n ) g(n) g(n) 为单次求组合数的复杂度。
ll qpow(ll x, ll n, ll mod) {
ll ans = 1;
while (n) {
if (n & 1)ans = (ans * x) % mod;
x = (x * x) % mod;
n >>= 1;
}
return ans % mod;
}
ll C(ll a, ll b, ll p){
//通过定理求组合数C(a, b)
if (a < b) return 0;
ll x = 1, y = 1;// x是分子,y是分母
for (int i = a, j = 1; j <= b; i--, j++){
x = x * i % p;
y = y * j % p;
}
return x * qpow(y, p - 2, p) % p;
}
ll lucas(ll a, ll b, int p){
//lucas定理求组合数
if (a < p && b < p) return C(a, b, p);
return C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}
素数在阶乘中的幂次
Legengre 在 1808 年指出 n ! n! n! 中含有的素数 p p p 的幂次为 ∑ j ≥ 1 ⌊ n / p j ⌋ \sum_{j\geq 1}\lfloor n/p^j\rfloor ∑j≥1⌊n/pj⌋。
证明:将 n ! n! n! 记为 1 × 2 × ⋯ × p × ⋯ × 2 p × ⋯ × ⌊ n / p ⌋ p × ⋯ × n 1\times 2\times \cdots \times p\times \cdots \times 2p\times \cdots \times \lfloor n/p\rfloor p\times \cdots \times n 1×2×⋯×p×⋯×2p×⋯×⌊n/p⌋p×⋯×n 那么其中 p p p 的倍数有 p × 2 p × ⋯ × ⌊ n / p ⌋ p = p ⌊ n / p ⌋ ⌊ n / p ⌋ ! p\times 2p\times \cdots \times \lfloor n/p\rfloor p=p^{\lfloor n/p\rfloor }\lfloor n/p\rfloor ! p×2p×⋯×⌊n/p⌋p=p⌊n/p⌋⌊n/p⌋! 然后在 ⌊ n / p ⌋ ! \lfloor n/p\rfloor ! ⌊n/p⌋! 中继续寻找 p p p 的倍数即可,这是一个递归的过程。为了方便记 ν ( n ! ) = ∑ j ≥ 1 ⌊ n / p j ⌋ \nu(n!)=\sum_{j\geq 1}\lfloor n/p^j\rfloor ν(n!)=∑j≥1⌊n/pj⌋。
另一种其他地方比较常见的公式,用到了 p 进制下各位数字和:
v p ( n ! ) = n − S p ( n ) p − 1 v_p(n!)=\frac{n-S_p(n)}{p-1} vp(n!)=p−1n−Sp(n)
与等比数列求和公式很相似。由于涉及各位数字和,利用数学归纳法可以轻松证明。
特别地,阶乘中 2 的幂次是:
v 2 ( n ! ) = n − S 2 ( n ) v_2(n!)=n-S_2(n) v2(n!)=n−S2(n)
素数在组合数中的幂次
组合数对一个数取模的结果,往往构成分形结构,例如谢尔宾斯基三角形就可以通过组合数模 2 得到。
v p ( C m n ) = S p ( n ) + S p ( m − n ) − S p ( m ) p − 1 v_p(C_m^n)=\frac{S_p(n)+S_p(m-n)-S_p(m)}{p-1} vp(Cmn)=p−1Sp(n)+Sp(m−n)−Sp(m)
如果仔细分析,p 是否整除组合数其实和上下标在 p 进制下减法是否需要借位有关。这就有了 Kummer 定理。
Kummer 定理:p 在组合数 C m n C_m^n Cmn 中的幂次,恰好是 p 进制下 m 减掉 n 需要借位的次数。
特别地,组合数中 2 的幂次是:
v 2 ( C m n ) = S 2 ( n ) + S 2 ( m − n ) − S 2 ( m ) v_2(C_m^n)=S_2(n)+S_2(m-n)-S_2(m) v2(Cmn)=S2(n)+S2(m−n)−S2(m)
Wilson 定理
对于素数 p p p 有 ( p − 1 ) ! ≡ − 1 ( m o d p ) (p-1)!\equiv -1\pmod p (p−1)!≡−1(modp)。
- 证明:我们知道在模奇素数 p p p 意义下, 1 , 2 , … , p − 1 1,2,\dots ,p-1 1,2,…,p−1 都存在逆元且唯一,那么只需要将一个数与其逆元配对发现其乘积均为(同余意义下) 1 1 1,但前提是这个数的逆元不等于自身。那么很显然 ( p − 1 ) ! m o d p (p-1)!\bmod p (p−1)!modp 就是逆元等于其自身的数的乘积,这两个数为 ± 1 \pm 1 ±1。在 p p p 为 2 2 2 时单独讨论即可。对于整数 n n n,令 ( n ! ) p (n!)_p (n!)p 表示所有小于等于 n n n 但不能被 p p p 整除的正整数的乘积,即 ( n ! ) p = n ! / ( ⌊ n / p ⌋ ! p ⌊ n / p ⌋ ) (n!)_p=n!/(\lfloor n/p\rfloor !p^{\lfloor n/p\rfloor}) (n!)p=n!/(⌊n/p⌋!p⌊n/p⌋)。
- Wilson 定理指出 ( p ! ) p = ( p − 1 ) ! ≡ − 1 ( m o d p ) (p!)_p=(p-1)!\equiv -1\pmod p (p!)p=(p−1)!≡−1(modp) 且可被推广至模素数 p p p 的幂次。
推论 1
对于素数 p p p 和正整数 q q q 有 ( p q ! ) p ≡ ± 1 ( m o d p q ) (p^q!)_p\equiv \pm 1\pmod{p^q} (pq!)p≡±1(modpq)。
依然考虑配对一个数与其逆元,也就是考虑关于 m m m 的同余方程 m 2 ≡ 1 ( m o d p q ) m^2\equiv 1\pmod{p^q} m2≡1(