卢卡斯定理

介绍

这是个用来求解大组合数取模意义下的值的算法。

要求取模的数是个质数。

算法

卢卡斯定理就是这样一条柿子:
( n m ) ≡ ( n   m o d   p m   m o d   p ) ( n ÷ p m ÷ p ) ( m o d p ) {n\choose m}\equiv{n \bmod p \choose m \bmod p}{n\div p \choose m\div p} \pmod p (mn)(mmodpnmodp)(m÷pn÷p)(modp)

(注意, ÷ \div ÷ 是整除。)

当我们有了这条结论之后,我们可以对 ( n ÷ p m ÷ p ) {n\div p \choose m\div p} (m÷pn÷p) 这部分不断使用卢卡斯定理,对 ( n   m o d   p m   m o d   p ) {n \bmod p \choose m \bmod p} (mmodpnmodp) 这一部分计算组合数。如果提前 O ( n ) O(n) O(n) 预处理阶乘以及阶乘的逆元,就可以做到 O ( l o g p n ) O(log_pn) O(logpn) 计算大组合数。

证明

显然 n n n 可以表示成 a p + b ap+b ap+b m m m 可以表示为 c p + d cp+d cp+d,那么上面的柿子可以变为:
( a p + b c p + d ) ≡ ( b d ) ( a c ) ( m o d p ) {ap+b \choose cp+d}\equiv{b \choose d} {a \choose c} \pmod p (cp+dap+b)(db)(ca)(modp)

那么有:
( 1 + x ) n ≡ ( 1 + x ) a p × ( 1 + x ) b ( m o d p ) ( 1 + x ) n ≡ ( ( 1 + x ) p ) a × ( 1 + x ) b ( m o d p ) \begin{aligned} (1+x)^n&\equiv(1+x)^{ap}\times (1+x)^b \pmod p\\ (1+x)^n&\equiv((1+x)^p)^a\times (1+x)^b \pmod p\\ \end{aligned} (1+x)n(1+x)n(1+x)ap×(1+x)b(modp)((1+x)p)a×(1+x)b(modp)

我们考虑转化里面 ( 1 + x ) p (1+x)^p (1+x)p 这一项,用神奇的二项式定理

( 1 + x ) p ≡ ∑ i = 0 p ( p i ) x i ( m o d p ) (1+x)^p \equiv \sum_{i=0}^p {p\choose i} x^i \pmod p\\ (1+x)pi=0p(ip)xi(modp)

i = 0 i=0 i=0 时,这一项的值为 1 1 1

i = p i=p i=p 时,这一项的值为 x p x^p xp

i ∈ ( 0 , p ) i\in(0,p) i(0,p) 时, ( p i ) = p ! i ! ( p − i ) ! {p\choose i}=\frac {p!} {i!(p-i)!} (ip)=i!(pi)!p! ,由于 p p p 是个质数,所以这个系数肯定是 p p p 的倍数,于是这一项为 0 0 0

这里就是普通卢卡斯定理的限制—— p p p 必须是质数——的缘由,如果 p p p 不是质数,那么就不能保证这个系数是 p p p 的倍数。而如果 p p p 是个质数,那么当 i ∈ ( 0 , p ) i\in (0,p) i(0,p) 时,分母部分不可能含有 p p p 这个因子,而分子里肯定含有 p p p 这个因子,所以总的这个系数肯定是 p p p 的倍数。

所以有
∑ i = 0 p ( p i ) x i ≡ 1 + x p ( m o d p ) \sum_{i=0}^p {p\choose i}x^i\equiv 1+x^p \pmod p i=0p(ip)xi1+xp(modp)

带回去有:
( 1 + x ) n ≡ ( 1 + x p ) a × ( 1 + x ) b ( m o d p ) ∑ i = 0 n ( n i ) x i ≡ ∑ i = 0 a ( a i ) x i p × ∑ i = 0 b ( b i ) x i ( m o d p ) \begin{aligned} (1+x)^n&\equiv (1+x^p)^a\times (1+x)^b \pmod p\\ \sum_{i=0}^n {n\choose i}x^i&\equiv \sum_{i=0}^a {a\choose i} x^{ip} \times \sum_{i=0}^b {b\choose i} x^i \pmod p \end{aligned} (1+x)ni=0n(in)xi(1+xp)a×(1+x)b(modp)i=0a(ia)xip×i=0b(ib)xi(modp)

左边这个多项式中, x c p + d x^{cp+d} xcp+d 的系数为 ( n c p + d ) {n\choose cp+d} (cp+dn),即 ( a p + b c p + d ) {ap+b\choose cp+d} (cp+dap+b)

因为 b < p b<p b<p,所以右边只有 x c p x^{cp} xcp x d x^d xd 这两项的积为 x c p + d x^{cp+d} xcp+d,而这两项的系数之积为 ( a c ) ( b d ) {a\choose c}{b\choose d} (ca)(db),所以有:
( a p + b c p + d ) ≡ ( b d ) ( a c ) ( m o d p ) {ap+b \choose cp+d}\equiv{b \choose d} {a \choose c} \pmod p (cp+dap+b)(db)(ca)(modp)

得证

模板题传送门

AC代码:

#include <cstdio>
#include <cstring>
#define ll long long

int t,n,m,p;
ll fac[100010];
ll ksm(ll x,int y)
{
	ll re=1,tot=x;
	while(y)
	{
		if(y&1)re=re*tot%p;
		tot=tot*tot%p;
		y>>=1;
	}
	return re;
}
ll C(int x,int y)
{
	if(x<y)return 0;
	return fac[x]*ksm(fac[y]*fac[x-y]%p,p-2)%p;
}
ll lucas(ll x,ll y)
{
	if(y==0)return 1ll;
	return lucas(x/p,y/p)*C(x%p,y%p)%p;
}

int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d %d %d",&n,&m,&p);
		fac[0]=1;
		for(int i=1;i<=p;i++)
		fac[i]=fac[i-1]*i%p;
		printf("%lld\n",lucas(n+m,m));
	}
}

瞎JB补充

英文名: l u c a s lucas lucas (好像有人叫 l u c a s s lucass lucass?)

卢卡斯定理还有另外一种形式:

对于 n , m n,m n,m 两个数,可以将他们表示为 p p p 进制下的数:
n = ( a 1 a 2 . . . a k ) ( p ) m = ( b 1 b 2 . . . b k ) ( p ) \begin{aligned} n&=(a_1a_2...a_k)_{(p)}\\ m&=(b_1b_2...b_k)_{(p)} \end{aligned} nm=(a1a2...ak)(p)=(b1b2...bk)(p)

那么有:
C n m = C a 1 b 1 × C a 2 b 2 × . . . × C a k b k C_n^m=C_{a_1}^{b_1} \times C_{a_2}^{b_2} \times ... \times C_{a_k}^{b_k} Cnm=Ca1b1×Ca2b2×...×Cakbk

这种形式和上面那种其实是等价的,想想就明白了。

一道练习题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值