码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 5201 The Monkey King(组合数学)(隔板法+容斥定理+费马小定理)

时间:2018-03-07 18:59:35      阅读:175      评论:0      收藏:0      [点我收藏+]

标签:monkey   key   .net   组合   gpo   一个   names   限制   print   

http://acm.hdu.edu.cn/showproblem.php?pid=5201
题意:给你n个桃子要你分给m只猴子,猴子可以得0个桃子,问有多少种方法,但是有一个限制条件: 第一只猴子分得的桃子数量一定大于其他猴子的桃子数。

思路:首先部门不考虑限制条件,那么这个问题就非常简单了,n个物品分成m组,允许某些组为空(这不就是隔板法吗!~~~!),简单答案就是组合:C(n+m-1,m-1);

           现在我们来考虑限制条件,由于至少k只猴子的桃子数大于第一只猴子的桃子数比较好算,假设第一只猴子得到了x个桃子,那么在剩下的m-1只猴子中选取 k只猴子也得到x个桃子,这个方法数为:C(m-1,k),

           还剩下t=n-(x+1)*k个桃子,把它分给除第一只猴子外的m-1猴子,C(t+m-1,m-2);利用容斥定理可以得到最后的答案=总答案-至少一只猴子的桃子数大于第一只猴子+至少两只猴子的桃子数大于第一只猴子-....+....

注意:组合数里面的n,m比较大,求阶乘的时候不好算,可以使用费马小定理先预处理了这些阶乘!a^(p-2)=a^-1(mod p)  (p为素数)。

 参考:http://blog.csdn.net/tc_to_top/article/details/48579971

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<queue>
 4 using namespace std;
 5 typedef long long ll;
 6 const int mod=1e9+7;
 7 const int maxn=2e5+10;
 8 
 9 int n,m;
10 ll fz[maxn];///分子的阶乘
11 ll fm[maxn];///(分母的阶乘)使用费马小定理求出分母的逆元
12             ///C(x,y)=fz[x]*fm[y]*fm[x-y];
13 ll Q_pow(ll x,ll y)///x^y
14 {
15     ll cnt=1;
16     while(y)
17     {
18         if(y&1)
19             cnt=cnt*x%mod;
20         x=x*x%mod;
21         y>>=1;
22     }
23     return cnt%mod;
24 }
25 void init()
26 {
27     fz[0]=fz[1]=1;
28     fm[0]=fm[1]=1;
29     for(int i=2;i<maxn-1;i++)
30     {
31         fz[i]=i*fz[i-1]%mod;
32         fm[i]=Q_pow(fz[i],mod-2);///费马小定理(P为素数):a^(p-2)=a^-1(mod p)
33     }
34 }
35 ll C(int x,int y)///组合数C(x,y)
36 {
37   return fz[x]*fm[y]%mod*fm[x-y]%mod;
38 }
39 ll solve(int x)///第一只猴子得到的桃子数为x
40 {
41     if(x==n)
42         return 1;
43     int k=0;
44     int t;
45     ll ans=0;
46     while(1)
47     {
48         if(k>m-1)
49             break;
50         t=n-(k+1)*x;///剩余桃子数
51         if(t<0)///剩余桃子数肯定不能小于0
52             break;
53         ll cnt=C(m-1,k)*C(t+m-2,m-2)%mod;
54         if(k&1)///k%2==1
55             ans=(ans+mod-cnt)%mod;
56         else
57             ans=(ans+cnt)%mod;
58         k++;
59     }
60     return ans;
61 }
62 int main()
63 {
64     int t;
65     scanf("%d",&t);
66     init();
67     while(t--)
68     {
69         scanf("%d %d",&n,&m);
70         if(m==1)
71         {
72             printf("1\n");
73             continue ;
74         }
75         ll ans=0;
76         for(int i=1;i<=n;i++)
77             ans=(ans+solve(i))%mod;
78         printf("%lld\n",ans);
79     }
80     return 0;
81 }

 

HDU 5201 The Monkey King(组合数学)(隔板法+容斥定理+费马小定理)

标签:monkey   key   .net   组合   gpo   一个   names   限制   print   

原文地址:https://www.cnblogs.com/Y-Meng/p/8523822.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!