Saving Beans HDU - 3037(题解)
原题
题目大意
题目要求把i颗豆(0<=i<=m)放进n个洞里有多少种情况.
题目分析
这道题可以看作是在m颗豆里面按顺序插入n+1个板,就是把这m颗豆分成n+1堆,其中n堆是要放入洞中的,还有1堆是不放进洞中的.这时候情况有(m+1)(m+2)...(m+n+1),又因为这些板是相同的,所以需要除掉它们的全排列即,(m+1)(m+2)...(m+n+1)/(n+1)n...321=!(m+n+1)/!(n+1)!(m).可知求的是C(m+n+1,m).p是质数,可以用lucas定理来求,即C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p,其中分隔出来的C(n%p,m%p)%p足够小,可以用逆元求出来,逆元a可以用ap-2来求,lucas定理可以用递归来实现,m为0时返回1并结束递归(这里记得注意一下C(n%p,m%p)中的m%p是有可能大于n%p的,这时答案为0).
代码
1 #include <cstdio> 2 #include <cmath> 3 #include <iostream> 4 #include <cstring> 5 #include <algorithm> 6 #include <vector> 7 #include <string> 8 #include <utility> 9 #include <queue> 10 #include <stack> 11 #include <map> 12 const int INF=0x3f3f3f3f; 13 using namespace std; 14 15 long long fac[100001]; 16 long long p; 17 18 void init(void) //阶乘预处理 19 { 20 fac[1]=fac[0]=1; 21 22 for(int i=2;i<p;i++) 23 { 24 fac[i]=fac[i-1]*i%p; 25 26 } 27 } 28 29 long long power(long long a,long long b) 30 { 31 long long res=1; 32 a%=p; 33 while(b) 34 { 35 if(b&1) res=res*a%p; 36 a=a*a%p; 37 b>>=1; 38 39 } 40 return res; 41 } 42 43 long long lucas(long long m,long long n) 44 { 45 if(!n) return 1; 46 if(m%p<n%p) return 0; 47 else return lucas(m/p,n/p)*fac[m%p]%p*power(fac[n%p]*fac[(m%p-n%p)],p-2)%p; 48 } 49 50 int main() 51 { 52 int t; 53 cin>>t; 54 while(t--) 55 { 56 long long n,m; 57 cin>>n>>m>>p; 58 init(); 59 60 long long ans; 61 ans=lucas(n+m,m); 62 cout<<ans<<endl; 63 } 64 return 0; 65 }