注意:Lucas 定理和扩展 Lucas 算法没有关系。取名“扩展 Lucas”仅仅是因为该算法能解决 Lucas 定理所解决的问题的推广情况。
Lucas(卢卡斯定理)
定理内容
Lucas(卢卡斯定理)是一个用于加快计算小质数模意义下的组合数的定理。
具体地,它能解决形如
(
n
m
)
m
o
d
p
\binom{n}{m} \bmod p
(mn)modp
的问题,其中
p
p
p 为质数。
公式为:
(
n
m
)
≡
(
⌊
n
p
⌋
⌊
m
p
⌋
)
(
n
m
o
d
p
m
m
o
d
p
)
(
m
o
d
p
)
\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
+
x
p
(
m
o
d
p
)
(1+x)^p \equiv 1+x^p \pmod p
(1+x)p≡1+xp(modp)
直接把左边二项式展开,得到
1
+
(
p
1
)
x
+
(
p
2
)
x
2
+
⋯
+
(
p
p
)
x
p
1+\binom{p}{1}x+\binom{p}{2}x^2+\cdots+\binom{p}{p}x^p
1+(1p)x+(2p)x2+⋯+(pp)xp
注意到
p
p
p 是质数,所以无法在组合数分母上被约去,因此第二项到第
p
p
p 项都是
p
p
p 的倍数。因此上式成立。
令 n = k 1 p + c 1 n=k_1p+c_1 n=k1p+c1, m = k 2 p + c 2 m=k_2p+c_2 m=k2p+c2。
考虑
(
1
+
x
)
n
(1+x)^n
(1+x)n。其在模
p
p
p 意义下有如下等式:
(
1
+
x
)
n
=
(
1
+
x
)
k
1
p
+
c
1
=
(
1
+
x
)
k
1
p
(
1
+
x
)
c
1
=
(
1
+
x
p
)
k
1
(
1
+
x
)
c
1
\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
展开这个式子,考察
x
m
x^m
xm 项。
在 ( 1 + x ) n (1+x)^n (1+x)n 中其系数为 ( n m ) \binom{n}{m} (mn)。在 ( 1 + x p ) k 1 ( 1 + x ) c 1 (1+x^p)^{k_1}(1+x)^{c_1} (1+xp)k1(1+x)c1 中,次数分解为 k 2 p + c 2 k_2p+c_2 k2p+c2。
分别从两个二项式中提取次数,可得系数为
(
k
1
k
2
)
(
c
1
c
2
)
\binom{k_1}{k_2}\binom{c_1}{c_2}
(k2k1)(c2c1)
于是
(
n
m
)
≡
(
k
1
k
2
)
(
c
1
c
2
)
(
m
o
d
p
)
\binom{n}{m} \equiv \binom{k_1}{k_2}\binom{c_1}{c_2} \pmod p
(mn)≡(k2k1)(c2c1)(modp)
ExLucas(扩展卢卡斯)
简介
ExLucas(Extended Lucas,扩展卢卡斯)是一个用于加快计算小模数下的模意义组合数的算法。
具体地,它能解决形如
(
n
m
)
m
o
d
p
\binom{n}{m} \bmod p
(mn)modp
的问题,其中
p
p
p 不一定是质数。
算法的核心是利用质因数分解与中国剩余定理,将问题转化为质数幂次模意义下的计算,然后利用式子进行问题规模的缩小并递归求解。
算法与原理
流程与原理
令模数为 p p p,其质因数分解 p = p 1 α 1 p 2 α 2 ⋯ p=p_1^{\alpha_1}p_2^{\alpha_2}\cdots p=p1α1p2α2⋯
我们求解如下几个方程
{
(
n
m
)
≡
a
1
(
m
o
d
p
1
α
1
)
(
n
m
)
≡
a
2
(
m
o
d
p
2
α
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)⋯
得出所有
a
i
a_i
ai 后,用 CRT 合并即可求出答案。以下我们只考虑解决
(
n
m
)
m
o
d
P
k
\binom{n}{m} \bmod P^k
(mn)modPk
其中
P
P
P 为质数。
考虑正常计算组合数的方法:
(
n
m
)
=
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! 的
P
P
P 因子个数,有
(
n
m
)
≡
n
!
P
f
(
n
)
m
!
P
f
(
m
)
(
n
−
m
)
!
P
f
(
n
−
m
)
P
f
(
n
)
−
f
(
m
)
−
f
(
n
−
m
)
(
m
o
d
P
k
)
\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
!
P
f
(
x
)
m
o
d
P
k
\frac{x!}{P^{f(x)}} \bmod P^k
Pf(x)x!modPk
将
x
x
x 及以下所有
P
P
P 的倍数提出在外:
x
!
=
(
P
×
2
P
×
⋯
)
(
1
×
2
×
⋯
)
x! = (P\times 2P\times \cdots)(1 \times 2 \times \cdots)
x!=(P×2P×⋯)(1×2×⋯)
提出
P
P
P:
x
!
=
P
⌊
x
P
⌋
(
⌊
x
P
⌋
)
!
(
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×⋯),其在模
P
k
P^k
Pk 意义下显然有周期。
具体地,该式实际形式为
(
1
×
2
×
⋯
×
(
P
k
−
1
)
×
(
P
k
+
1
)
×
(
P
k
+
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)×⋯)
而在模
P
k
P^k
Pk 意义下,其等同于
(
1
×
2
×
⋯
×
(
P
k
−
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
⌊
x
P
⌋
(
⌊
x
P
⌋
)
!
(
∏
i
=
1
,
P
∤
i
P
k
i
)
⌊
x
P
k
⌋
(
∏
i
=
1
,
P
∤
i
x
m
o
d
P
k
i
)
(
m
o
d
P
k
)
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)
最后那两个部分都是可以暴力的,而
(
⌊
x
P
⌋
)
!
(\lfloor\frac{x}{P}\rfloor)!
(⌊Px⌋)! 可以递归求解。
然后考察
f
(
x
)
f(x)
f(x) 怎么求。注意到一个方法是先筛选所有至少有一个
P
P
P 因子的数,然后筛选所有至少有两个
P
P
P 因子的数,依此类推。这个过程就是不断找一个数以内
P
P
P 的倍数的过程,公式化为下式:
f
(
x
)
=
f
(
⌊
x
P
⌋
)
+
⌊
x
P
⌋
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
!
P
f
(
x
)
g(x)=\frac{x!}{P^{f(x)}}
g(x)=Pf(x)x! 的递归表达式:
g
(
x
)
≡
g
(
⌊
x
P
⌋
)
(
∏
i
=
1
,
P
∤
i
P
k
i
)
⌊
x
P
k
⌋
(
∏
i
=
1
,
P
∤
i
x
m
o
d
P
k
i
)
(
m
o
d
P
k
)
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)
最后就是
P
f
(
n
)
−
f
(
m
)
−
f
(
n
−
m
)
P^{f(n)-f(m)-f(n-m)}
Pf(n)−f(m)−f(n−m) 的求解了。注意到
f
f
f 的递归式,直接求解就是
O
(
log
P
n
)
O(\log_P n)
O(logPn) 的。
总结:
- 首先将 p p p 质因数分解为质数次幂,对每个质数次幂作为模数分别求解。
- 对 n ! n! n!, m ! m! m!, ( n − m ) ! (n-m)! (n−m)! 使用上述方法求 g g g。递归下去,层内暴力算乘积。
- 计算 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 ( log p ) O(\log p) O(logp),不过瓶颈不在这,没必要。
第二步总复杂度 O ( ∑ P log P n P k ) O(\sum_P \log_P n P^k) O(∑PlogPnPk),上界是 O ( p log n ) O(p\log n) O(plogn)。
第三步总复杂度 O ( ∑ P ( log P n + log n ) ) O(\sum_P (\log_P n + \log n)) O(∑P(logPn+logn)),上界是 O ( log p log n ) O(\log p\log n) O(logplogn)。
最后一步复杂度 O ( log 2 p ) O(\log^2 p) O(log2p)。