【模板】卢卡斯定理/Lucas 定理
题目链接:luogu P3807
题目大意
求 C(n,n+m)%p 的值。
p 保证是质数。
思路
Lucas 定理内容
对于非负整数
n
n
n,
m
m
m,质数
p
p
p,有:
C
m
n
≡
∏
i
=
0
k
C
m
i
n
i
(
m
o
d
p
)
C_m^n\equiv \prod\limits_{i=0}^kC_{m_i}^{n^i}(\bmod\ p)
Cmn≡i=0∏kCmini(mod p)
其中
m
=
m
k
p
k
+
.
.
.
+
m
1
p
+
m
0
m=m_kp^k+...+m_1p+m_0
m=mkpk+...+m1p+m0,
n
=
n
k
p
k
+
.
.
.
+
n
1
p
+
n
0
n=n_kp^k+...+n_1p+n_0
n=nkpk+...+n1p+n0。(其实就是
n
,
m
n,m
n,m 的
p
p
p 进制展开)
那我们一般做题用的是递推式,也就是
C
m
n
≡
C
⌊
m
/
p
⌋
⌊
n
/
p
⌋
C
m
m
o
d
p
n
m
o
d
p
(
m
o
d
p
)
C_m^n\equiv C_{\left\lfloor m/p\right\rfloor}^{\left\lfloor n/p\right\rfloor}C_{m\bmod p}^{n\bmod p}(\bmod\ p)
Cmn≡C⌊m/p⌋⌊n/p⌋Cmmodpnmodp(mod p)
(当
n
>
m
n>m
n>m 时,我们规定
C
m
n
=
0
C_{m}^n=0
Cmn=0)
啥时候会用
我们有时候要算组合数,可能 C m n C_{m}^n Cmn 的 n , m n,m n,m 很大,这时候一般做题就会让他取模一个数 m o d p \bmod \ p mod p。
那如果
p
>
m
p>m
p>m,我们可以愉快的用这个式子求:
C
m
n
=
m
!
n
!
(
m
−
n
)
!
C_{m}^n=\dfrac{m!}{n!(m-n)!}
Cmn=n!(m−n)!m!
算出
n
!
n!
n! 和
(
m
−
n
)
!
(m-n)!
(m−n)! 的逆元,就可以搞。
可当 m ⩾ p m\geqslant p m⩾p 的时候,分母的乘法逆元可能不存在。(因为 x x x 是 p p p 的倍数的话 x x x 就没有模 p p p 的逆元)
那这个时候我们就可以用 Lucas 定理把这个组合数拆成几个 m < p m<p m<p 的,就可以搞了。
证明
证明 Lucas 定理之前,我们先证明两个式子。
式一:
C
p
i
≡
p
i
C
p
−
1
i
−
1
≡
0
(
m
o
d
p
)
,
(
1
⩽
i
<
p
)
C_p^i\equiv \frac{p}{i}C_{p-1}^{i-1}\equiv0(\bmod\ p),(1\leqslant i<p)
Cpi≡ipCp−1i−1≡0(mod p),(1⩽i<p)
证明:
C
p
i
=
p
!
i
!
(
p
−
i
)
!
=
p
i
(
p
−
1
)
!
(
i
−
1
)
!
(
p
−
1
−
(
i
−
1
)
)
!
=
p
i
C
p
−
1
i
−
1
C_p^i=\dfrac{p!}{i!(p-i)!}=\dfrac{p}{i}\dfrac{(p-1)!}{(i-1)!(p-1-(i-1))!}=\frac{p}{i}C_{p-1}^{i-1}
Cpi=i!(p−i)!p!=ip(i−1)!(p−1−(i−1))!(p−1)!=ipCp−1i−1
由于
1
⩽
i
<
p
1\leqslant i<p
1⩽i<p,故
i
i
i 会有
p
p
p 的逆元
i
n
v
i
inv_i
invi
p
i
C
p
−
1
i
−
1
=
p
×
i
n
v
i
×
C
p
−
1
i
−
1
\frac{p}{i}C_{p-1}^{i-1}=p\times inv_i\times C_{p-1}^{i-1}
ipCp−1i−1=p×invi×Cp−1i−1
那这个地方都是
p
p
p 的倍数,那它被
p
p
p 取模一定是
0
0
0,故得证。
式二:
根据二项式定理:
(
1
+
n
)
p
≡
C
p
0
+
C
p
1
x
+
.
.
.
+
C
p
p
−
1
x
p
−
1
+
C
p
p
x
p
(
m
o
d
p
)
(1+n)^p\equiv C_p^0+C_p^1x+...+C_p^{p-1}x^{p-1}+C_p^px^p(\bmod\ p)
(1+n)p≡Cp0+Cp1x+...+Cpp−1xp−1+Cppxp(mod p)
再根据式一
C
p
i
≡
0
(
m
o
d
p
)
,
(
1
⩽
i
<
p
)
C_p^i\equiv0(\bmod\ p),(1\leqslant i<p)
Cpi≡0(mod p),(1⩽i<p),可以得到
(
1
+
n
)
p
≡
C
p
0
+
C
p
p
x
p
≡
1
+
x
p
(
m
o
d
p
)
(1+n)^p\equiv C_p^0+C_p^px^p\equiv 1+x^p(\bmod\ p)
(1+n)p≡Cp0+Cppxp≡1+xp(mod p)
接着我们开始证明,先设
⌊
m
/
p
⌋
=
q
m
,
⌊
n
/
p
⌋
=
q
n
,
m
m
o
d
p
=
r
m
,
n
m
o
d
p
=
r
n
\left\lfloor m/p\right\rfloor=q_m,\left\lfloor n/p\right\rfloor=q_n,m\bmod p=r_m,n\bmod p=r_n
⌊m/p⌋=qm,⌊n/p⌋=qn,mmodp=rm,nmodp=rn。
那有
m
=
q
m
p
+
r
m
,
n
=
q
n
p
+
r
n
m=q_mp+r_m,n=q_np+r_n
m=qmp+rm,n=qnp+rn。
接着我们继续用二项式定理:
(
1
+
x
)
m
=
∑
i
=
1
m
C
m
i
x
i
(1+x)^m=\sum\limits_{i=1}^{m}C_{m}^ix^i
(1+x)m=i=1∑mCmixi
然后我们把左边给化简:
(
1
+
x
)
m
=
(
1
+
x
)
q
m
p
+
r
m
=
(
1
+
x
)
q
m
p
⋅
(
1
+
x
)
r
m
=
[
(
1
+
x
)
p
]
q
m
⋅
(
1
+
x
)
r
m
≡
(
1
+
x
p
)
q
m
⋅
(
1
+
x
)
r
m
[
式
二
]
≡
∑
i
=
1
q
m
C
q
m
i
x
i
p
∑
i
=
1
r
m
C
r
m
i
x
i
(
m
o
d
p
)
\begin{aligned}(1+x)^m & =(1+x)^{q_mp+r_m} \\ & =(1+x)^{q_mp}\cdot(1+x)^{r_m} \\& =[(1+x)^p]^{q_m}\cdot(1+x)^{r_m}\\&\equiv(1+x^p)^{q_m}\cdot(1+x)^{r_m}[式二]\\&\equiv\sum\limits_{i=1}^{q_m}C_{q_m}^ix^{ip}\sum\limits_{i=1}^{r_m}C_{r_m}^{i}x^i(\bmod\ p)\end{aligned}
(1+x)m=(1+x)qmp+rm=(1+x)qmp⋅(1+x)rm=[(1+x)p]qm⋅(1+x)rm≡(1+xp)qm⋅(1+x)rm[式二]≡i=1∑qmCqmixipi=1∑rmCrmixi(mod p)
那就有:
∑
i
=
1
m
C
m
i
x
i
≡
∑
i
=
1
q
m
C
q
m
i
x
i
p
∑
i
=
1
r
m
C
r
m
i
x
i
(
m
o
d
p
)
\sum\limits_{i=1}^{m}C_{m}^ix^i\equiv\sum\limits_{i=1}^{q_m}C_{q_m}^ix^{ip}\sum\limits_{i=1}^{r_m}C_{r_m}^{i}x^i(\bmod\ p)
i=1∑mCmixi≡i=1∑qmCqmixipi=1∑rmCrmixi(mod p)
那对于任意一个数
z
z
z,必然会有一组
i
,
j
i,j
i,j 满足
x
z
=
x
p
i
x
j
x^z=x^{pi}x^j
xz=xpixj
不难看出这其实就是满足
z
=
p
i
+
j
z=pi+j
z=pi+j,所以当且仅当
i
=
⌊
z
p
⌋
,
j
=
z
m
o
d
p
i=\left\lfloor \dfrac{z}{p}\right\rfloor,j=z\bmod p
i=⌊pz⌋,j=zmodp。
那也就是说左边的
i
i
i 取任意一个,右边都有一个新的跟它对于恒等。
左边
i
=
x
i=x
i=x,右边的就分别是
i
=
⌊
x
p
⌋
,
i
=
x
m
o
d
p
i=\left\lfloor \dfrac{x}{p}\right\rfloor,i=x\bmod p
i=⌊px⌋,i=xmodp
那当
i
=
x
i=x
i=x,就有:
C
m
n
x
n
=
C
q
m
q
n
x
q
n
p
C
r
m
r
n
x
r
n
C
m
n
x
n
=
C
q
m
q
n
C
r
m
r
n
x
q
n
p
+
r
n
C
m
n
x
n
=
C
q
m
q
n
C
r
m
r
n
x
n
\begin{aligned}C_m^nx^n&=C_{q_m}^{q_n}x^{q_np}C_{r_m}^{r_n}x^{r_n}\\C_m^nx^n&=C_{q_m}^{q_n}C_{r_m}^{r_n}x^{q_np+r_n}\\C_m^nx^n&=C_{q_m}^{q_n}C_{r_m}^{r_n}x^n\end{aligned}
CmnxnCmnxnCmnxn=CqmqnxqnpCrmrnxrn=CqmqnCrmrnxqnp+rn=CqmqnCrmrnxn
两边同乘
i
n
v
(
x
n
)
inv(x^n)
inv(xn),就有了
C
m
n
=
C
q
m
q
n
C
r
m
r
n
C_{m}^n=C_{q_m}^{q_n}C_{r_m}^{r_n}
Cmn=CqmqnCrmrn
得证。
本题
其实逆元的话直接要用的话直接 x p − 2 m o d p x^{p-2}\bmod p xp−2modp 更好,不用像我这样线性求出每个。
代码
#include<cstdio>
#define ll long long
using namespace std;
ll T, n, m, p;
ll jc[100001], inv[100001];
ll ksm(ll x, ll y) {
ll re = 1;
while (y) {
if (y & 1) re = (re * x) % p;
x = (x * x) % p;
y >>= 1;
}
return re;
}
ll C(ll x, ll y) {//暴力算组合数
if (x > y) return 0;
return ((jc[y] * inv[x]) % p * inv[y - x]) % p;
}
ll work(ll n, ll m) {//Lucas 定理
if (!n) return 1;
return (work(n / p, m / p) * C(n % p, m % p)) % p;
}
int main() {
scanf("%lld", &T);
while (T--) {
scanf("%lld %lld %lld", &n, &m, &p);
jc[0] = 1;
for (ll i = 1; i <= p; i++)//预处理阶乘与其逆元
jc[i] = (jc[i - 1] * i) % p;
inv[p - 1] = ksm(jc[p - 1], p - 2);
for (ll i = p - 2; i >= 0; i--)
inv[i] = (inv[i + 1] * (i + 1)) % p;
printf("%lld\n", work(n, n + m));
}
return 0;
}