[BZOJ3027][Ceoi2004]Sweet 容斥+组合数

3027: [Ceoi2004]Sweet

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 135  Solved: 66
[Submit][Status][Discuss]

Description

John得到了n罐糖果。不同的糖果罐,糖果的种类不同(即同一个糖果罐里的糖果种类是相同的,不同的糖果罐里的糖果的种类是不同的)。第i个糖果罐里有 mi个糖果。John决定吃掉一些糖果,他想吃掉至少a个糖果,但不超过b个。问题是John 无法确定吃多少个糖果和每种糖果各吃几个。有多少种方法可以做这件事呢?  
  
 

Input


从标准输入读入每罐糖果的数量,整数a到b 
 
John能够选择的吃掉糖果的方法数(满足以上条件)  
 

Output


 
把结果输出到标准输出(把答案模 2004 输出) 

1<=N<=10,0<=a<=b<=10^7,0<=Mi<=10^6

Sample Input

2 1 3
3
5

Sample Output

9

HINT

 

(1,0),(2,0),(3,0),(0,1),(0,2),(0,3),(1,1),(1,2),(2,1) 

 

Source

 

对糖果是否装满容斥,通过插板法计算方案。

模数不为质数但n很小,可以将模数乘n!之后除n!。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 #define LL long long
 8 using namespace std;
 9 LL n,a,b;
10 LL m[50];
11 LL mod=2004,mul=1;
12 LL c(LL x,LL y) {
13     if(x<y) return 0;
14     LL ans=1;
15     for(int i=x;i>=x-y+1;i--) ans=1LL*ans*i%mod;
16     return (ans/mul)%2004LL;
17 }
18 LL cnt(LL x) {
19     LL ans=0;
20     for(int i=0;i<(1<<n);i++) {
21         LL f=0,s=x;
22         for(int j=1;j<=n;j++) if((1<<(j-1))&i) f++,s-=m[j]+1;
23         if(s<0) continue;
24         if(f&1) ans-=c(s+n,n);
25         else ans+=c(s+n,n);
26         ans%=2004LL;
27     }
28     return ans;
29 }
30 int main() {
31     scanf("%lld%lld%lld",&n,&a,&b);
32     for(int i=1;i<=n;i++) scanf("%lld",&m[i]);
33     for(int i=1;i<=n;i++) mod*=i,mul*=i;
34     printf("%lld",((cnt(b)-cnt(a-1))%2004LL+2004LL)%2004LL);
35 }
View Code

 

posted @ 2017-12-27 15:49  wls001  阅读(218)  评论(0编辑  收藏  举报