3027: [Ceoi2004]Sweet
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 71 Solved: 34Description
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
【分析】
就是分成(<=b) - (<= a-1)的。
然后每个糖果罐容斥,枚举哪些超过了的。
假设减掉之后剩下最多选x个糖果
就是$C_{0+n-1}^{n-1}+C_{1+n-1}^{n-1}+C_{2+n-1}^{n-1}+...+C_{x+n-1}^{n-1}$
求和之后就是$C_{x+n}^{n}$
但是!!!模数可能没有逆元,又不能n^2预处理。。
【怎么办呢???
【又涨姿势。。
首先都是$C_{x}^{n}$的形式,即$dfrac{x!}{(x-n )!}/(n!)$
n!很小,让$mod=Mod*n!$
计算的时候模mod,最后除以n!,再模Mod。。。
就可以了。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Mod 2004 8 #define Maxm 10000010 9 #define LL long long 10 11 int w[15],n; 12 LL mul; 13 14 int get_c(int x,int y) 15 { 16 if(x<y) return 0; 17 LL mod=mul*Mod,ans=1; 18 for(int i=x;i>=x-y+1;i--) ans=1LL*ans*i%mod; 19 return (ans/mul)%Mod; 20 } 21 22 int cal(int x) 23 { 24 int ans=0; 25 for(int i=0;i<(1<<n);i++) 26 { 27 int ss=0,sm=x; 28 for(int j=1;j<=n;j++) if((1<<j-1)&i) 29 { 30 ss++;sm-=w[j]+1; 31 } 32 if(sm<0) continue; 33 if(ss&1) ans-=get_c(sm+n,n); 34 else ans+=get_c(sm+n,n); 35 ans%=Mod; 36 } 37 return ans; 38 } 39 40 int main() 41 { 42 int a,b; 43 scanf("%d%d%d",&n,&a,&b); 44 mul=1;for(int i=2;i<=n;i++) mul=mul*i; 45 for(int i=1;i<=n;i++) scanf("%d",&w[i]); 46 printf("%d ",((cal(b)-cal(a-1))%Mod+Mod)%Mod); 47 return 0; 48 }
2017-04-25 21:25:39