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 }

 

posted @ 2019-03-07 19:30  VBL  阅读(81)  评论(0编辑  收藏  举报