标签:its 注意 evo 解题思路 c++ 描述 lan for har
\(John\)得到了\(n\)罐糖果。不同的糖果罐,糖果的种类不同(即同一个糖果罐里的糖果种类是相同的,不同的糖果罐里的糖果的种类是不同的)。第\(i\)个糖果罐里有\(m_{i}\)个糖果。\(John\) 决定吃掉一些糖果,他想吃掉至少\(a\)个糖果,但不超过\(b\)个。问题是 \(John\)无法确定吃多少个糖果和每种糖果各吃几个。有多少种方法可以做这件事呢?
生成函数题,考虑对于第\(i\)堆吃\(j\)个糖果的方案并写成封闭模式为
那么对于吃\(i\)个的方案数为
对于\((1-x)^{-n}\)我们使用牛顿广义二项式展开可得\(\begin{aligned}(1-x)^{-n}=\sum_{k=0}^{\infty}\dbinom{-n}{k}(-x)^k=\sum_{k=0}^{\infty}(-1)^k\dbinom{n+k-1}{k}(-x)^k=\sum_{k=0}^{\infty}\dbinom{n+k-1}{k}x^k\end{aligned}\)
对于后面的柿子我们直接暴搜,怎么暴力怎么来就可以,对于前面的\(\begin{aligned}\sum_{k=0}^{\infty}\dbinom{n+k-1}{k}x^k\end{aligned}\),我们考虑对答案的贡献,对于答案是\(x^a\)~\(x^b\)对应的系数,则设\(\prod_{i=1}^n(1-x^{m_i+1})\)枚举到了\(x^k\),则为\(\begin{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)\)
模数不是质数,组合数用定义进行计算
#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\n" , ans);
return ~~(0^_^0);
}
int Ame__ = Ame_();
int main(){;}
/*
2 1 3
3
5
*/
-----\(\mathcal{Ame\_\_}\)
标签:its 注意 evo 解题思路 c++ 描述 lan for har
原文地址:https://www.cnblogs.com/Ame-sora/p/13603968.html