【hdu3037】Saving Beans——组合数取模

题目链接

题目的大意是求在n棵树上采摘不超过m颗豆子的方案数,要求答案对给定的p取模,同时保证p为质数。

奉上大神关于这道题的公式的推导及变形:戳这里

最后就是求C(n+m,m)%p啦~

这里因为p<=1e5,而n和m又很大,所以应该要用到Lucas定理:

Lucas(n,m,p)=C(n%p,m%p)*Lucas(n/p,m/p,p),证明有兴趣的自行百度。

注意要预处理阶乘才不会TLE,因为p是要求读入的所以每组数据都要预处理一次。

由费马小定理可知b关于p(要求p是质数)的逆元是b^(p-2),所以这里还要写一个快速幂取模求逆元。

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 typedef long long LL;
 5 using namespace std;
 6 LL n,m,p;
 7 LL jie[100005];
 8 LL read()
 9 {
10     LL ans=0,f=1;char c=getchar();
11     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
12     while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();}
13     return ans*f;
14 } 
15 LL kuai(LL a,LL b)
16 {
17     LL res=1;
18     while(b){
19         if(b&1)res=res*a%p;
20         a=(a*a)%p;
21         b>>=1;
22     }
23     return res;
24 }
25 LL C(LL x,LL y)
26 {
27     if(x<y)return 0;
28     LL ans;
29     ans=jie[x]*kuai(jie[y],p-2)%p*kuai(jie[x-y],p-2)%p;
30     return ans;
31 }
32 LL lucas(LL x,LL y)
33 {
34     LL ans=1;
35     while(x&&y&&ans){
36         if(x%p<y%p)return 0;
37         ans=(ans*C(x%p,y%p))%p;
38         x/=p;
39         y/=p;
40     }
41     return ans;
42 }
43 int main()
44 {
45     LL t;
46     t=read();
47     while(t--){
48         n=read();m=read();p=read();
49         jie[0]=jie[1]=1;
50         for(int i=2;i<=p;i++)jie[i]=jie[i-1]*i%p;
51         printf("%lld\n",lucas(n+m,m));
52     }
53     return 0;
54 }
hdu3037

 

posted @ 2017-08-28 13:17  Child-Single  阅读(177)  评论(0编辑  收藏  举报