1. 程式人生 > >【BZOJ 3027】 3027: [Ceoi2004]Sweet (容斥原理+組合計數)

【BZOJ 3027】 3027: [Ceoi2004]Sweet (容斥原理+組合計數)

3027: [Ceoi2004]Sweet

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 71  Solved: 34

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

【分析】   就是分成(<=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\n",((cal(b)-cal(a-1))%Mod+Mod)%Mod); 47 return 0; 48 }
View Code

2017-04-25 21:25:39