Lucas 定理: C(n,m)%p
=( C(n/p,m/p)*C(n%p,m%p) )%p
=( C(n0,m0) * C(n1,m1) *...* C(nk,mk) )%p; 其中 n=(n0 n1 n2 .. nk)p, m=(m0 m1 m2 ... mk)p; 注:()p 表示p进制
HDU 3037 http://acm.hdu.edu.cn/showproblem.php?pid=3037
题意: 问 将不多于m颗相同的豆,放到n棵不同的树上,有多少种方法%p
<=> 将m颗相同的豆,放到n+1棵不同的树上,有多少种方法%p
<=> C(n+m,n)%p 隔板法
=>n,m达到10^9 太大
=>Lucas
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctype.h>
#include<algorithm>
#include<stack>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
#define pi acos(-1.0)
#define eps 1e-7
#define INF 0x3f3f3f3f
#define maxn 200005
typedef long long ll;
int exgcd(int a,int b,int &x,int &y){
int d=a;
if(b!=0){
d=exgcd(b,a%b,y,x);
y-=(a/b)*x;
}
else {x=1;y=0;}
return d;
}
int pul[maxn]; //记录(1*..*i)%p
ll c(int a,int b,int p){ //快速求C(a,b)%p
if(b>a) return 0;
int x,y;
exgcd(((ll)pul[b]*pul[a-b])%p,p,x,y);
if(x<0) x+=p;
return ((ll)pul[a]*x)%p;
}
ll C(int n,int m,int p){
if(m==0) return 1;
else return ((ll)c(n%p,m%p,p)*C(n/p,m/p,p))%p;
}
int main(){
int t;
int n,m,p;
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&n,&m,&p);
pul[0]=1;
for(int i=1;i<p;i++)
pul[i]=((ll)pul[i-1]*i)%p;
int ans=C(n+m,m,p);
printf("%d\n",ans);
}
return 0;
}
HDU 4349 http://acm.hdu.edu.cn/showproblem.php?pid=4349
Lucas的应用
若C(n,m)%p!=0
由于 C(n,m)%p
=( C(n0,m0) * C(n1,m1) *...* C(nk,mk) )%p; (#)
若所有的 ni>=mi 则 (#)!=0,反之(#)=0;
所以ans=(n0+1)*(n1+1)*...(nk+1);
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<map>
using namespace std;
typedef long long ll;
int main(){
ll n;
while(scanf("%I64d",&n)!=EOF){
ll ans=1;
while(n>0)
ans*=(n%2+1);n/=2;
printf("%I64d\n",ans);
}
}