Lucas定理介绍及证明
0. 介绍
lucas定理用来求组合数取模的,在这里记录一下。
假设 p p p是一个质数,现在要求组合数 ( n m ) {n \choose m} (mn)模 p p p。
根据带余数除法可得
n = s p + q , 0 ≤ q < p m = t p + r , 0 ≤ r < p n=sp+q, \quad 0\le q <p\\ m=tp+r,\quad 0\le r <p\\ n=sp+q,0≤q<pm=tp+r,0≤r<p
那么有
(
n
m
)
=
(
s
t
)
(
q
r
)
(
m
o
d
p
)
{n\choose m}={s \choose t }{q \choose r}\quad (\bmod \ p)
(mn)=(ts)(rq)(mod p)
1. 证明
不难得到
(
1
+
x
)
n
=
(
1
+
x
)
s
p
+
q
=
(
1
+
x
)
s
p
(
1
+
x
)
q
=
[
(
1
+
x
)
p
]
s
(
1
+
x
)
q
\begin{align*} (1+x)^{n}&=(1+x)^{sp+q}\\ &=(1+x)^{sp}(1+x)^{q}\\ &=[(1+x)^{p}]^{s}(1+x)^q \end{align*}
(1+x)n=(1+x)sp+q=(1+x)sp(1+x)q=[(1+x)p]s(1+x)q
引入结论
(
p
i
)
m
o
d
p
=
0
,
1
≤
i
<
p
{p \choose i} \bmod p = 0, \quad 1 \le i < p
(ip)modp=0,1≤i<p
根据二项式定理
(
1
+
x
)
p
=
1
+
x
p
+
∑
i
=
1
p
−
1
(
p
i
)
x
i
(1+x)^{p}=1+x^{p}+\sum_{i=1}^{p-1}{p \choose i}x^i
(1+x)p=1+xp+i=1∑p−1(ip)xi
综合上面两式可以得到
(
1
+
x
)
p
≡
1
+
x
p
(
m
o
d
p
)
(1+x)^p \equiv1+x^p \quad (\bmod\ p)
(1+x)p≡1+xp(mod p)
进而
[
(
1
+
x
)
p
]
s
≡
(
1
+
x
p
)
s
≡
∑
i
=
0
s
(
s
i
)
x
i
p
[(1+x)^p]^s \equiv (1+x^{p})^s \equiv \sum_{i=0}^{s}{s \choose i}x^{ip}
[(1+x)p]s≡(1+xp)s≡i=0∑s(is)xip
同理可得
(
1
+
x
)
q
≡
∑
j
=
0
q
(
q
j
)
x
j
(1+x)^q \equiv \sum_{j=0}^{q}{q \choose j}x^{j}
(1+x)q≡j=0∑q(jq)xj
又由二项式定理可得,在
(
1
+
x
)
n
中
(1+x)^n中
(1+x)n中
x
m
x^{m}
xm的系数为
(
n
m
)
=
(
s
p
+
q
t
p
+
r
)
{n \choose m}={sp+q \choose tp+r}
(mn)=(tp+rsp+q)
整理上面各式后可以得到
(
n
m
)
≡
(
s
p
+
q
t
p
+
r
)
≡
∑
i
=
0
s
(
s
i
)
x
i
p
∑
j
=
0
q
(
q
j
)
x
j
(
m
o
d
p
)
{n \choose m} \equiv {sp+q \choose tp+r} \\\equiv \sum_{i=0}^{s} {s \choose i} x^{ip} \sum_{j=0}^{q}{q \choose j}x_j\quad ( \bmod\ p)
(mn)≡(tp+rsp+q)≡i=0∑s(is)xipj=0∑q(jq)xj(mod p)
观察可得,右边的式子只有当
i
=
t
j
=
r
i=t\ j=r
i=t j=r时才能取到
x
m
x^{m}
xm项。
因此
(
n
m
)
≡
(
s
t
)
(
q
r
)
(
m
o
d
p
)
{n \choose m} \equiv {s \choose t}{q \choose r} \quad (\ \bmod\ p)
(mn)≡(ts)(rq)( mod p)
2. 代码
以Luogu p3807为例
#include <iostream>
using ll = long long;
static constexpr int MAXN = 100010;
ll bc[MAXN+1];
ll qpow(ll x, ll y, ll p) {
ll tmp = x % p;
ll ans = 1;
while(y) {
if (y & 1) ans = ans * tmp % p;
tmp = tmp * tmp % p;
y >>= 1;
}
return ans;
}
ll C(ll n, ll m, ll p) {
if (n < m) return 0;
return (bc[n] * qpow(bc[m], p - 2, p ) % p * qpow(bc[n - m], p - 2, p) % p);
}
ll Lucas(ll n, ll m, ll p) {
if (!m) return 1;
return Lucas( n / p, m / p, p) * C(n % p, m % p, p) % p;
}
int main( int argc, char *argv[])
{
ll n;
ll m;
ll p;
int t;
std::cin >> t;
while (t--) {
std::cin >> n >> m >> p;
bc[0] = 1;
for (int i = 1; i <= p;i++) {
bc[i] = bc[i - 1] * i % p;
}
ll ans = Lucas(n + m, m, p);
std::cout << ans << std::endl;
}
return 0;
}
3. 参考
百度-Lucas定理