1. 程式人生 > >hdu3037(盧卡斯定理+組合數取模)

hdu3037(盧卡斯定理+組合數取模)

題目
題意:松鼠要過冬,然後要在n棵樹上存不超過m個果子。求有多少種存法。

思路:一共有n棵樹,每棵樹上有xi個果子,問題就可以抽象成x1+x2+....+xn=m這樣一個等式。而且xi是可以為0的。
這樣的話就可以寫成n個0和m個1寫在一行,然後用插板法求解。
但是隻是普通的插板法只能解決所有果子都放到樹上的情況,所以我們這裡人為的新增一個板子,一定是放在最右邊的,然後用來記放在地上的果子,這樣的話有n+m個空(最左邊0的左邊也是可以插板子的,代表一棵樹上不放果子,是一樣的),n個板子,然後答案就是C(nn+m).但是這裡的n和m特別大,然而要取模的mod比較小,所以要用盧卡斯定理

#include<cstdio>
#include<algorithm> #include<cstring> using namespace std; const int fcnt=100101; long long mod,p; long long fac[fcnt]; void getfac(int mo) { fac[0]=1; for(int i=1;i<=mo;i++) fac[i]=fac[i-1]*i%mod; } long long quickpow(long long a,long long b) { if(b<0)return 0; long
long ret=1; a%=mod; while(b) { if(b&1) ret=(ret*a)%mod; b>>=1; a=(a*a)%mod; } return ret; } long long inv(long long a) { return quickpow(a,mod-2); } long long c(long long n,long long m) { if(n<m) return 0; return
fac[n]*inv(fac[m])%mod*inv(fac[n-m])%mod; } long long Lucas(long long n,long long m) { if(m==0) return 1; return Lucas(n/p,m/p)*c(n%p,m%p)%p; } int main() { int t; while(~scanf("%d",&t)) { while(t--) { long long int t1,t2; scanf("%lld %lld %lld",&t1,&t2,&p); mod=p; getfac(p); long long ans=Lucas(t1+t2,t1); printf("%lld\n",ans); } } }