题目描述
(John)得到了(n)罐糖果。不同的糖果罐,糖果的种类不同(即同一个糖果罐里的糖果种类是相同的,不同的糖果罐里的糖果的种类是不同的)。第(i)个糖果罐里有(m_{i})个糖果。(John) 决定吃掉一些糖果,他想吃掉至少(a)个糖果,但不超过(b)个。问题是 (John)无法确定吃多少个糖果和每种糖果各吃几个。有多少种方法可以做这件事呢?
解题思路
生成函数题,考虑对于第(i)堆吃(j)个糖果的方案并写成封闭模式为
那么对于吃(i)个的方案数为
对于((1-x)^{-n})我们使用牛顿广义二项式展开可得(egin{aligned}(1-x)^{-n}=sum_{k=0}^{infty}dbinom{-n}{k}(-x)^k=sum_{k=0}^{infty}(-1)^kdbinom{n+k-1}{k}(-x)^k=sum_{k=0}^{infty}dbinom{n+k-1}{k}x^kend{aligned})
对于后面的柿子我们直接暴搜,怎么暴力怎么来就可以,对于前面的(egin{aligned}sum_{k=0}^{infty}dbinom{n+k-1}{k}x^kend{aligned}),我们考虑对答案的贡献,对于答案是(x^a)~(x^b)对应的系数,则设(prod_{i=1}^n(1-x^{m_i+1}))枚举到了(x^k),则为(egin{aligned}sum_{i=a-k}^{b-k}dbinom{n+i-1}{i}end{aligned}),展开后对其用加法公式(dbinom{n}{m}=dbinom{n-1}{m}+dbinom{n-1}{m-1})进行化简可得为(dbinom{n+b-k}{b-k}-dbinom{n+a-k-1}{a-k-1}),然后就可以做了,总体时间复杂度为(O(2^n))
细节注意
模数不是质数,组合数用定义进行计算
(Code)
#include<bits/stdc++.h>
#define LL long long
#define _ 0
using namespace std;
/*Grievous Lady*/
template <typename _n_> void mian(_n_ & _x_){
_x_ = 0;int _m_ = 1;char buf_ = getchar();
while(buf_ < '0' || buf_ > '9'){if(buf_ == '-')_m_ =- 1;buf_ = getchar();}
do{_x_ = _x_ * 10 + buf_ - '0';buf_ = getchar();}while(buf_ >= '0' && buf_ <= '9');_x_ *= _m_;
}
const int kato = 20;
LL fac = 1 , ans , n , a , b , m[kato];
#define mod 2004
inline int c(int a , int b){
if(a < b) return 0;
LL res = 1 , tmp = fac * mod;
for(int i = a - b + 1;i <= a;i ++){
res = res * i % tmp;
}
return (res / fac) % mod;
}
void dfs(int x , int opt , int t){
if(x == n + 1){
ans = (ans + opt * (c(n + b - t , n) - c(n + a - t - 1 , n))) % mod;
return;
}
dfs(x + 1 , opt , t) , dfs(x + 1 , - opt , t + m[x] + 1);
}
inline int Ame_(){
mian(n) , mian(a) , mian(b);
for(int i = 1;i <= n;i ++){
mian(m[i]);
fac = fac * i;
}
dfs(1 , 1 , 0);
if(ans < 0) ans += mod;
printf("%lld
" , ans);
return ~~(0^_^0);
}
int Ame__ = Ame_();
int main(){;}
/*
2 1 3
3
5
*/
-----(mathcal{Ame\_\_})