【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 没法肯定吃多少个糖果和每种糖果各吃几个。有多少种方法能够作这件事呢?  

ios

Input


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

Output


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

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

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) 

blog

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:39ip

相关文章
相关标签/搜索