[JSOI2011]分特产

题目大意:
  有n个人,m种物品,第i种物品有a[i]个。
  现在给这些人发物品,要求每个人至少发到一件物品。
  问有多少种不同的发法。

思路:
  首先不考虑“每个人至少发到一件物品”的限制,那么答案应该是$prodinom{n-1+a[j]}{n-1}$。
  考虑容斥,答案为都取的方案数-1个人不取的方案数+2个人不取的方案数...都不取的方案数。
  假设有i个人不取,那么方案数就是$prodinom{n-i-1+a[j]}{n-i-1}$。
  最后加减几次即可。

 1 #include<cstdio>
 2 #include<cctype>
 3 typedef long long int64;
 4 inline int getint() {
 5     register char ch;
 6     while(!isdigit(ch=getchar()));
 7     register int x=ch^'0';
 8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 9     return x; 
10 }
11 const int N=1000,M=1000,mod=1e9+7;
12 int a[M],c[N<<1][N<<1];
13 int main() {
14     const int n=getint(),m=getint();
15     for(register int i=0;i<m;i++) {
16         a[i]=getint();
17     }
18     for(register int i=0;i<n<<1;i++) {
19         c[i][0]=1;
20         for(register int j=1;j<=i;j++) {
21             c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
22         }
23     }
24     int ans=0;
25     for(register int i=0;i<=n;i++) {
26         int tmp=c[n][i];
27         for(register int j=0;j<m;j++) {
28             tmp=(int64)tmp*c[n-i-1+a[j]][n-i-1]%mod;
29         }
30         tmp*=i&1?-1:1;
31         ans=((ans+tmp)%mod+mod)%mod;
32     }
33     printf("%d
",ans);
34     return 0;
35 }
原文地址:https://www.cnblogs.com/skylee03/p/8183385.html