题目描述:
John得到了n罐糖果。不同的糖果罐,糖果的种类不同(即同一个糖果罐里的糖果种类是相同的,不同的糖果罐里的糖果的种类是不同的)。第i个糖果罐里有 mi个糖果。John决定吃掉一些糖果,他想吃掉至少a个糖果,但不超过b个。问题是John 无法确定吃多少个糖果和每种糖果各吃几个。有多少种方法可以做这件事呢?
题目分析:
求吃
k
k
k个糖果的方案数即下面这个方程的整数解个数:
x
1
+
x
2
+
.
.
.
+
x
n
=
k
(
0
≤
x
i
≤
m
i
)
x_1+x_2+...+x_n=k\\(0\le x_i\le m_i)
x1+x2+...+xn=k(0≤xi≤mi)
用隔板法及容斥原理可知解的个数为
∑
S
∈
{
1
,
2..
n
}
(
−
1
)
∣
S
∣
C
k
−
(
∑
i
∈
S
m
i
+
1
)
+
n
−
1
n
−
1
\sum_{S\in\{1,2..n\}}(-1)^{|S|}C_{k-(\sum_{i\in S}m_i+1)+n-1}^{n-1}
∑S∈{1,2..n}(−1)∣S∣Ck−(∑i∈Smi+1)+n−1n−1
现在 k k k可以取 [ a , b ] [a,b] [a,b],所以相当于要求 ∑ S ∈ { 1 , 2.. n } ( − 1 ) ∣ S ∣ ∑ k = 0 N C k − ( ∑ i ∈ S m i + 1 ) + n − 1 n − 1 \sum_{S\in\{1,2..n\}}(-1)^{|S|}\sum_{k=0}^NC_{k-(\sum_{i\in S}m_i+1)+n-1}^{n-1} ∑S∈{1,2..n}(−1)∣S∣∑k=0NCk−(∑i∈Smi+1)+n−1n−1
当 k < ∑ i ∈ S m i + 1 k<\sum_{i\in S}m_i+1 k<∑i∈Smi+1时,C=0;当 k ≥ ∑ i ∈ S m i + 1 k\ge \sum_{i\in S}m_i+1 k≥∑i∈Smi+1时,后面的C的和即为 ∑ p = 0 N − ∑ i ∈ S m i + 1 C p + n − 1 n − 1 = C n − 1 n − 1 + C n n − 1 + C n + 1 n − 1 . . . \sum_{p=0}^{N-\sum_{i\in S}m_i+1}C_{p+n-1}^{n-1}=C_{n-1}^{n-1}+C_n^{n-1}+C_{n+1}^{n-1}... p=0∑N−∑i∈Smi+1Cp+n−1n−1=Cn−1n−1+Cnn−1+Cn+1n−1...
因为 C n − 1 n − 1 = C n n = 1 C_{n-1}^{n-1}=C_n^n=1 Cn−1n−1=Cnn=1,且 C i j = C i − 1 j − 1 + C i − 1 j C_i^j=C_{i-1}^{j-1}+C_{i-1}^j Cij=Ci−1j−1+Ci−1j,所以上式 = C n n + C n n − 1 + C n + 1 n − 1 . . . = C n + 1 n + C n + 1 n − 1 + C n + 2 n − 1 . . . = C n + 2 n + C n + 2 n − 1 + . . . = C N − ∑ i ∈ S m i + 1 + n n =C_n^n+C_{n}^{n-1}+C_{n+1}^{n-1}...=C_{n+1}^n+C_{n+1}^{n-1}+C_{n+2}^{n-1}...=C_{n+2}^n+C_{n+2}^{n-1}+...=C_{N-\sum_{i\in S}m_i+1+n}^n =Cnn+Cnn−1+Cn+1n−1...=Cn+1n+Cn+1n−1+Cn+2n−1...=Cn+2n+Cn+2n−1+...=CN−∑i∈Smi+1+nn
对于模数为2004的情况,这位仁兄VisJiao的博客说的很好:
另外,上面的推导过程可以用生成函数,详见这篇blog
Code:
#include<cstdio>
#include<algorithm>
#define maxn 15
using namespace std;
const int mod = 2004;
int n,L,R,a[maxn],fac,ans;
int C(int n,int m){//m==n
if(n<m) return 0;
static const long long Mod = 1ll*fac*mod;//long long attention!
long long ret=1;
for(int i=n-m+1;i<=n;i++) ret=ret*i%Mod;
return ret/fac;
}
int main()
{
scanf("%d%d%d",&n,&L,&R);
fac=1; for(int i=2;i<=n;i++) fac*=i;
for(int i=0;i<n;i++) scanf("%d",&a[i]);
for(int s=0;s<1<<n;s++){
int typ=1,tmp=0;
for(int i=0;i<n;i++) if(s>>i&1) typ=-typ,tmp+=a[i]+1;
ans=(ans+typ*(C(R-tmp+n,n)-C(L-1-tmp+n,n)))%mod;
}
printf("%d\n",(ans+mod)%mod);
}