9.27T1 组合数+容斥原理

1.分特产2414

 (cut)

【问题描述】

JYY 带队参加了若干场ACM/ICPC 比赛,带回了许多土特产,要分给实验室的同学们。

JYY 想知道,把这些特产分给N 个同学,一共有多少种不同的分法?当然,JYY 不希望任何一个同学因为没有拿到特产而感到失落,所以每个同学都必须至少分得一个特产。

例如,JYY 带来了2 袋麻花和1 袋包子,分给A 和B 两位同学,那么共有4 种不同的

分配方法:

A:麻花,B:麻花、包子

A:麻花、麻花,B:包子

A:包子,B:麻花、麻花

A:麻花、包子,B:麻花

【输入】

输入数据第一行是同学的数量N 和特产的数量M。

第二行包含M 个整数,表示每一种特产的数量。

N, M 不超过1000,每一种特产的数量不超过1000.

【输出】

输出一行,不同分配方案的总数。由于输出结果可能非常巨大,你只需要输出最终结果

MOD 1,000,000,007 的数值就可以了。

【样例输入】

5 4
1 3 3 5

 

 

 

题目来源于JSOI2011

我今天早上才做了一道容斥原理的题目。。。结果就考了,我还是没有做起,考完之后看了下成绩还是倒数第二,倒数第一爆了0

光是这一道题只有后面的几个人没写起,其他人全AC

所有的物品,将其划分成n部分,每部分不能为空,问总的方案数
可以如果利用插板法的话,把n个相同的小球放到m个不同的盒子里有C(n+m−1,m−1)种方案,不过这个只能求出允许空的方案数,对每一种特产都讨论的话,总方案数即为根据容斥原理,答案应该为至少0个盒子为空的-至少1个盒子为空的+至少2个盒子为空的-…至少n个盒子为空的
那么我们可以每一次强制i个盒子为空,剩余的再像上面一样选就行了

答案就是

上面是官方解法,下面谈谈我的感受

这道题其实当时有那么一丝丝的感受是容斥原理,但是我也不知道怎么容斥,但我也没想到是枚举多少个空的来进行容斥

首先我们考虑把每一种物品分开来处理,也就是一类一类的处理,最后把他们相乘就是当前的状态

首先我们明显知道如果m个小球给n个人(允许空出来),答案就是C[n-1][n+m-1]。这个还是知道的

显然我们要排除有空的情况,对于空出来的情况我们有空1人,2,3,4.。。。直到n

至少空 i 个人,那么就剩余 n-i 个人,状态数就是C[n-i-1][n+m-1-i]前面必须还要乘上C[i][n]代表选哪几个空着

然后跑一边容斥原理。。。。

显然我做不起。。。。慢慢写吧。。。。

code:

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 int c[2005][2005];
 5 const int mod=1e9+7;
 6 int s[5000];
 7 int main(){
 8     for(int i=0;i<=2000;i++)c[i][0]=1; 
 9     for(int i=1;i<=2000;i++)
10         for(int j=1;j<=2000;j++)
11             c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
12     int n,m;
13     cin>>n>>m;
14     long long ans=0;
15     for(int i=1;i<=m;i++)cin>>s[i];
16     for(int i=0;i<=n;i++){//枚举至少几个人是空的 
17         long long now=1;
18         for(int j=1;j<=m;j++){
19             now*=c[n-i-1+s[j]][n-i-1];
20             now%=mod;
21         }
22         if(i%2){
23             ans-=c[n][i]*now;
24             ans=(ans+mod)%mod;
25         }
26         else{
27             ans+=c[n][i]*now;
28             ans%=mod;
29         }
30     } 
31     ans+=mod,ans%=mod;
32     cout<<ans;
33     return 0;
34 }

over

posted @ 2018-09-27 15:01  saionjisekai  阅读(73)  评论(0)    收藏  举报