注意:Lucas 定理和扩展 Lucas 算法没有关系。取名“扩展 Lucas”仅仅是因为该算法能解决 Lucas 定理所解决的问题的推广情况。
Lucas(卢卡斯定理)
定理内容
Lucas(卢卡斯定理)是一个用于加快计算小质数模意义下的组合数的定理。
具体地,它能解决形如
(nm) mod p
\binom{n}{m} \bmod p
(mn)modp
的问题,其中 ppp 为质数。
公式为:
(nm)≡(⌊np⌋⌊mp⌋)(n mod pm mod p)(modp)
\binom{n}{m} \equiv \binom{\lfloor\frac{n}{p}\rfloor}{\lfloor\frac{m}{p}\rfloor} \binom{n \bmod p}{m \bmod p} \pmod p
(mn)≡(⌊pm⌋⌊pn⌋)(mmodpnmodp)(modp)
证明
首先证明一个式子
(1+x)p≡1+xp(modp)
(1+x)^p \equiv 1+x^p \pmod p
(1+x)p≡1+xp(modp)
直接把左边二项式展开,得到
1+(p1)x+(p2)x2+⋯+(pp)xp
1+\binom{p}{1}x+\binom{p}{2}x^2+\cdots+\binom{p}{p}x^p
1+(1p)x+(2p)x2+⋯+(pp)xp
注意到 ppp 是质数,所以无法在组合数分母上被约去,因此第二项到第 ppp 项都是 ppp 的倍数。因此上式成立。
令 n=k1p+c1n=k_1p+c_1n=k1p+c1,m=k2p+c2m=k_2p+c_2m=k2p+c2。
考虑 (1+x)n(1+x)^n(1+x)n。其在模 ppp 意义下有如下等式:
(1+x)n=(1+x)k1p+c1=(1+x)k1p(1+x)c1=(1+xp)k1(1+x)c1
\begin{aligned}
& (1+x)^n \\
= & (1+x)^{k_1p+c_1} \\
= & (1+x)^{k_1p} (1+x)^{c_1} \\
= & (1+x^p)^{k_1}(1+x)^{c_1} \\
\end{aligned}
===(1+x)n(1+x)k1p+c1(1+x)k1p(1+x)c1(1+xp)k1(1+x)c1
展开这个式子,考察 xmx^mxm 项。
在 (1+x)n(1+x)^n(1+x)n 中其系数为 (nm)\binom{n}{m}(mn)。在 (1+xp)k1(1+x)c1(1+x^p)^{k_1}(1+x)^{c_1}(1+xp)k1(1+x)c1 中,次数分解为 k2p+c2k_2p+c_2k2p+c2。
分别从两个二项式中提取次数,可得系数为
(k1k2)(c1c2)
\binom{k_1}{k_2}\binom{c_1}{c_2}
(k2k1)(c2c1)
于是
(nm)≡(k1k2)(c1c2)(modp)
\binom{n}{m} \equiv \binom{k_1}{k_2}\binom{c_1}{c_2} \pmod p
(mn)≡(k2k1)(c2c1)(modp)
ExLucas(扩展卢卡斯)
简介
ExLucas(Extended Lucas,扩展卢卡斯)是一个用于加快计算小模数下的模意义组合数的算法。
具体地,它能解决形如
(nm) mod p
\binom{n}{m} \bmod p
(mn)modp
的问题,其中 ppp 不一定是质数。
算法的核心是利用质因数分解与中国剩余定理,将问题转化为质数幂次模意义下的计算,然后利用式子进行问题规模的缩小并递归求解。
算法与原理
流程与原理
令模数为 ppp,其质因数分解 p=p1α1p2α2⋯p=p_1^{\alpha_1}p_2^{\alpha_2}\cdotsp=p1α1p2α2⋯
我们求解如下几个方程
{(nm)≡a1(modp1α1)(nm)≡a2(modp2α2)⋯
\left\{
\begin{aligned}
&\binom{n}{m} \equiv a_1 \pmod {p_1^{\alpha_1}} \\
&\binom{n}{m} \equiv a_2 \pmod {p_2^{\alpha_2}} \\
&\cdots
\end{aligned}
\right.
⎩⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎧(mn)≡a1(modp1α1)(mn)≡a2(modp2α2)⋯
得出所有 aia_iai 后,用 CRT 合并即可求出答案。以下我们只考虑解决
(nm) mod Pk
\binom{n}{m} \bmod P^k
(mn)modPk
其中 PPP 为质数。
考虑正常计算组合数的方法:
(nm)=n!m!(n−m)!
\binom{n}{m} = \frac{n!}{m!(n-m)!}
(mn)=m!(n−m)!n!
无法在此处使用该方法,因为逆元可能不存在。
一个数在模意义下存在逆元的充要条件是其与模数互质。因此我们考虑把每个数的模数因子都提出去计算,这样就会互质,就可以求逆元了。
于是令 f(x)f(x)f(x) 为 x!x!x! 的 PPP 因子个数,有
(nm)≡n!Pf(n)m!Pf(m)(n−m)!Pf(n−m)Pf(n)−f(m)−f(n−m)(modPk)
\binom{n}{m} \equiv \frac{\frac{n!}{P^{f(n)}}}{\frac{m!}{P^{f(m)}}\frac{(n-m)!}{P^{f(n-m)}}} P^{f(n)-f(m)-f(n-m)} \pmod {P^k}
(mn)≡Pf(m)m!Pf(n−m)(n−m)!Pf(n)n!Pf(n)−f(m)−f(n−m)(modPk)
于是问题转化为求
x!Pf(x) mod Pk
\frac{x!}{P^{f(x)}} \bmod P^k
Pf(x)x!modPk
将 xxx 及以下所有 PPP 的倍数提出在外:
x!=(P×2P×⋯ )(1×2×⋯ )
x! = (P\times 2P\times \cdots)(1 \times 2 \times \cdots)
x!=(P×2P×⋯)(1×2×⋯)
提出 PPP:
x!=P⌊xP⌋(⌊xP⌋)!(1×2×⋯ )
x!=P^{\lfloor\frac{x}{P}\rfloor} (\lfloor\frac{x}{P}\rfloor)! (1\times 2 \times \cdots)
x!=P⌊Px⌋(⌊Px⌋)!(1×2×⋯)
后面的 (1×2×⋯ )(1 \times 2 \times \cdots)(1×2×⋯),其在模 PkP^kPk 意义下显然有周期。
具体地,该式实际形式为
(1×2×⋯×(Pk−1)×(Pk+1)×(Pk+2)×⋯ )
(1\times 2\times \cdots \times (P^k-1) \times (P^k+1) \times (P^k+2) \times \cdots)
(1×2×⋯×(Pk−1)×(Pk+1)×(Pk+2)×⋯)
而在模 PkP^kPk 意义下,其等同于
(1×2×⋯×(Pk−1)×1×2×⋯ )
(1\times 2\times \cdots \times (P^k-1) \times 1 \times 2 \times \cdots)
(1×2×⋯×(Pk−1)×1×2×⋯)
我们把该式写成公式化表达
x!≡P⌊xP⌋(⌊xP⌋)!(∏i=1,P∤iPki)⌊xPk⌋(∏i=1,P∤ix mod Pki)(modPk)
x! \equiv P^{\lfloor\frac{x}{P}\rfloor} (\lfloor\frac{x}{P}\rfloor)! (\prod_{i=1,P\nmid i}^{P^k} i)^{\lfloor\frac{x}{P^k}\rfloor}(\prod_{i=1,P\nmid i}^{x \bmod P^k} i) \pmod {P^k}
x!≡P⌊Px⌋(⌊Px⌋)!(i=1,P∤i∏Pki)⌊Pkx⌋(i=1,P∤i∏xmodPki)(modPk)
最后那两个部分都是可以暴力的,而 (⌊xP⌋)!(\lfloor\frac{x}{P}\rfloor)!(⌊Px⌋)! 可以递归求解。
然后考察 f(x)f(x)f(x) 怎么求。注意到一个方法是先筛选所有至少有一个 PPP 因子的数,然后筛选所有至少有两个 PPP 因子的数,依此类推。这个过程就是不断找一个数以内 PPP 的倍数的过程,公式化为下式:
f(x)=f(⌊xP⌋)+⌊xP⌋
f(x) = f(\lfloor\frac{x}{P}\rfloor)+\lfloor\frac{x}{P}\rfloor
f(x)=f(⌊Px⌋)+⌊Px⌋
边界为 f(x)=0 (x<P)f(x)=0 \ (x<P)f(x)=0 (x<P)。
通过这个式子,我们也可以直接写出 g(x)=x!Pf(x)g(x)=\frac{x!}{P^{f(x)}}g(x)=Pf(x)x! 的递归表达式:
g(x)≡g(⌊xP⌋)(∏i=1,P∤iPki)⌊xPk⌋(∏i=1,P∤ix mod Pki)(modPk)
g(x) \equiv g(\lfloor\frac{x}{P}\rfloor) (\prod_{i=1,P\nmid i}^{P^k} i)^{\lfloor\frac{x}{P^k}\rfloor}(\prod_{i=1,P\nmid i}^{x \bmod P^k} i) \pmod {P^k}
g(x)≡g(⌊Px⌋)(i=1,P∤i∏Pki)⌊Pkx⌋(i=1,P∤i∏xmodPki)(modPk)
最后就是 Pf(n)−f(m)−f(n−m)P^{f(n)-f(m)-f(n-m)}Pf(n)−f(m)−f(n−m) 的求解了。注意到 fff 的递归式,直接求解就是 O(logPn)O(\log_P n)O(logPn) 的。
总结:
- 首先将 ppp 质因数分解为质数次幂,对每个质数次幂作为模数分别求解。
- 对 n!n!n!,m!m!m!,(n−m)!(n-m)!(n−m)! 使用上述方法求 ggg。递归下去,层内暴力算乘积。
- 计算 g(m)g(m)g(m),g(n−m)g(n-m)g(n−m) 的逆元,利用递归式计算 f(n),f(m),f(n−m)f(n),f(m),f(n-m)f(n),f(m),f(n−m) 求解。
- 将每个结果用 CRT 合并。
时间复杂度
第一步复杂度 O(p)O(\sqrt p)O(p)。如果预线性筛出最小质因子可以做到 O(logp)O(\log p)O(logp),不过瓶颈不在这,没必要。
第二步总复杂度 O(∑PlogPnPk)O(\sum_P \log_P n P^k)O(∑PlogPnPk),上界是 O(plogn)O(p\log n)O(plogn)。
第三步总复杂度 O(∑P(logPn+logn))O(\sum_P (\log_P n + \log n))O(∑P(logPn+logn)),上界是 O(logplogn)O(\log p\log n)O(logplogn)。
最后一步复杂度 O(log2p)O(\log^2 p)O(log2p)。