3027: [Ceoi2004]Sweet
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 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
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 }