版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/85409055
传送门
生成函数好题。
题意简述:给出n个盒子,第
个盒子里有
颗相同的糖(但不同盒子中的糖不相同),问有多少种选法可以从各盒子中选出数量在
之间的糖果。
思路:先对每个盒子构造出生成函数:
然后把所有盒子的生成函数乘起来:
这个时候考虑如何统计答案。
直接做很难,因此我们差分一下,转化成求
,
表示选出数量不超过
的糖果的方案数。
左边的一坨
的系数看成把
拆成
个自然数,为
右边的一坨爆搜即可。
然后对于右边搜出来的
,假设当前要求数量不超过
,那么这一种组合方式对答案的贡献就是:
这样就可以更新答案了。
注意模数的处理
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
typedef long long ll;
const int mod=2004;
int m[12],N,a,b,fac=1,sum=0;
inline int C(int n,int m){
if(n<m)return 0;
ll Mod=(ll)mod*fac,ret=1;
for(ri i=n-m+1;i<=n;++i)ret=(ll)i%Mod*ret%Mod;
return (ret/fac)%mod;
}
inline void dfs(int dep,int type,int idx,int lim){
if(dep==N+1){(sum+=type*C(lim+N-idx,N)%mod)%=mod;return;}
dfs(dep+1,type,idx,lim),dfs(dep+1,-type,idx+m[dep]+1,lim);
}
inline int calc(int lim){return sum=0,dfs(1,1,0,lim),sum;}
int main(){
scanf("%d%d%d",&N,&a,&b);
for(ri i=1;i<=N;++i)scanf("%d",&m[i]),fac*=i;
cout<<((calc(b)-calc(a-1))%mod+mod)%mod;
return 0;
}