Lucas定理

内容

\[C^{n}_{m}\equiv C^{\lfloor \frac{n}{p}\rfloor}_{\lfloor \frac{m}{p}\rfloor} \times C^{n\%p}_{m\%p}\quad(mod\;p) \]

条件是 \(p\) 为质数。

\(Lucas\) 定理的主要作用是当组合数过大,无法处理其中 \(n\)\(m\) 的阶乘。通过展开将其表示成累积形式。

复杂度为 \(O(log^n)\)

注意,由于实际上是将问题转移到 \(p\) 身上,所以 \(Lucas\) 的局限是 \(p\) 不能太大。

证明

  • 首先提出一个引理:\(p\mid C^{i}_{p}\quad(p=1,2,3,\cdots,p-1)\)

    证明如下:

    \[\bf 原式等于:\scr \frac{\overbrace{p(p-1)\cdots (p-i+1)}^{i}}{i!} \]

    我们知道这个式子最后是整数,但是可以知道,小于 \(p\) 的数中只有 \(1\) 可以整除它,即除完后 \(p\) 这个因子被保留了下来,当然可以被 \(p\) 整除。

下面正式开始证明。

利用了二项式展开,已知:

\[(1+x)^{np+m}\equiv ((1+x)^p)^n\times(1+x)^{m}\quad(mod\;p) \]

我们知道,在 \((1+x)^p\) 的二项式展开式里,所有项前面都有一个 \(C^{i}_{p}\) ,那么除了 \(1\)\(x^p\) 两项,其他都可以被 \(p\) 整除。所以上式等同于:

\[(1+x^p)^n\times(1+x)^m\equiv\sum^{n}_{i=1}C^{i}_{n}x^{ip}\;\sum^{m}_{j=1}C^{j}_{m}x^j\quad(mod\;p) \]

那么,在项 \(x^{rp+s}\) 项前的系数,用原二项式展开式推出来的式子表示应该是一样的:

\[C^{rp+s}_{np+m}\equiv C^{r}_{n}\;C^{s}_{m}\quad(mod\;p) \]

即为:

\[C^{n}_{m}\equiv C^{\lfloor \frac{n}{p}\rfloor}_{\lfloor \frac{m}{p}\rfloor} \times C^{n\%p}_{m\%p}\quad(mod\;p) \]

从另一个角度来看,其实是对 \(n\)\(m\) 进行 \(p\) 进制展开。

MOD 及奇怪的小细节

luogu P3807

实际操作时 \(n\%p\) 项小于 \(p\) 可以直接算,但是 \(\lfloor \frac{n}{p}\rfloor\) 项要继续递归求解。

还有一个问题要注意,计算中, \(n\%p\) 是可能比 \(m\%p\) 大的,要怎么处理呢?

从组合意义上,算 \(0\) 当然是没错,即为:一旦有 \(n\%p\)\(m\%p\) 大,就会是 \(p\) 的整倍数。

结论很奇怪,我们还是来证明一下:

\[\bf 设 \;\scr a=np+m,b=kp+s\quad \bf 其中\;\scr m>s,k>n\\ \bf那么:\;\rm C^{a}_{b}=\frac{(kp+s)(kp+s-1)\cdots(np+m+1)}{((k-n)p+(s-m))!} \]

分子中有 \(k-n\)\(i\times p\) 项;当 \(s<m\) ,即 \(s-m <0\) 时,分母只有 \(k-n-1\)\(i\times p\) 项。

可见最后有一个因子 \(p\) 被保留下来了。当然这时模 \(p\) 值为 \(0\)

最后上代码:

\(\frak code\)

#include<cstdio>
#include<algorithm>
using namespace std;


int t;
int n,m,mod,ans;
int fac[100005];

int get_inv(int x,int p){
	int ret=1;
	int q=p-2;
	while(q>0){
		if(q&1) ret=(1ll*ret*x)%p;
		x=(1ll*x*x)%p;
		q>>=1;
	}
	return ret;	
} 

int c(int a,int b,int p){
	if(b<a) return 0;	
	return (1ll*(1ll*fac[b]*get_inv(fac[a],p))*get_inv(fac[b-a],p))%p;
}

int lucas(int a,int b,int p){
	if(b==0) return 1;
	return (1ll*lucas(a/p,b/p,p)*c(a%p,b%p,p)%p);
}



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

-EOF-
posted @ 2020-01-27 02:30  T_horn  阅读(158)  评论(0编辑  收藏  举报