卢卡斯定理:
符号定义:
C(n,m),n中选m个的组合
p:任意素数
卢卡斯定理就是为了求在模p域下,当n和m都很大的时候C(n,m)的值。
卢卡斯定理:
C(s*p+q,t*p+r)=C(s,t)*C(q,r);
用文字表达就是:
在模p域下,C(n,m)就是n和m对写成p进制,各个位上的组合和积。
证明:
用多项式系数可以证明,数学归纳法也可以证明。下面给出多项式系数的证明:
C(s*p+q,t*p+r)可以表示为(1+x)^(s*p+q)中x^(t*p+r)项的系数
考虑上式中x^(t*p+r)的系数,当i=t,j=r时为x^(t*p+r)的系数,因此:
C(s*p+q,t*p+r)=C(s,t)*C(q,j);
证毕。
例题:hdu 3037
给定n,m,p,实际上就是求C(n+m,n);
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<map>
#include<string>
#include<queue>
#include<vector>
#include<list>
//#pragma comment(linker,"/STACK:1024000000,1024000000")
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;
int n,m,mod;
ll fac[100018];
ll pow_m(ll a,ll n)
{
ll res=1;
while(n)
{
if(n%2) res*=a,res%=mod;
a=a*a;
a%=mod;
n/=2;
}
return res;
}
ll inv(ll a,ll mod)
{
return pow_m(a,mod-2);
}
ll C(ll n,ll m)
{
if(n<m) return 0;
return (fac[n]*inv(fac[m],mod)%mod)*inv(fac[n-m],mod)%mod;
}
ll lucas(ll n,ll m,ll mod)
{
ll res=0;
if(n+m==0) return 1;
return C(n%mod,m%mod)*lucas(n/mod,m/mod,mod)%mod;
}
int main()
{
fac[0]=1;
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&mod);
for(int i=1; i<mod; i++) fac[i]=fac[i-1]*i%mod;
printf("%lld\n",lucas(n+m,n,mod));
}
return 0;
}
卢卡斯定理就是为了求在模p域下,当n和m都很大的时候C(n,m)的值