bzoj 3027: [Ceoi2004]Sweet (生成函数)
题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=3027。
题目大意:有$n$种数,每种有$C_i$个,问你在这些数中取出$[l,r]$个,问你有多少种不同的取法,答案对2004取模。
数据范围:$n≤10$,$C_i≤10^6$,$1≤l<r≤10^7$。
我们不妨设$f(n)$表示不超过$n$的数的取法之和。
则答案显然为$f(r)-f(l-1)$,下面来推导f(x)。
显然,$f(m)$等于多项式$\Pi_{i=1}^{n} \sum_{j=1}^{C_i}x^i$[0,m]的系数和。
考虑到$C_i$很大,如果直接多项式乘法,会$T$,必须化简。
原式
$=\Pi_{i=1}^n \frac{1-x^{C_i} } {1-x}$。
$=\frac{\Pi_{i=1}^{n} (1-x^{C_i})}{(1-x)^n}$。
$=\Pi_{i=1}^{n} (1-x^{C_i}) \sum_{j=-1}^{\infty} \binom{n+j}{n-1}x^(j+1)$
考虑式子的前半部分,不难发现,该部分最多只有$2^n$个位置是非零的,显然我们只需要处理这部分,并不需要对整个多项式做乘法。实现该步骤一个dfs即可。
对于后半部分,假设求f(m)过程中前面通过dfs连乘出的单项式次数为k,系数为p,那么需要累加的答案显然多项式$p \times \sum_{j=-1}^{m-k-1} \binom{n+j}{n-1}x^(j+1)$。
然后根据组合数的相关公式进行化简,得到$p \times \binom{n+m-k-1}{n-1}$。
然后就愉快地昨晚啦
1 #include<bits/stdc++.h> 2 #define L long long 3 #define MOD 2004 4 using namespace std; 5 6 L n,a,b,now,ans=0; 7 L m[15]={0},mul=0; 8 9 L C(int n,int m){ 10 if(n<m) return 0; 11 L ans=1,mod=mul*MOD; 12 for(L i=n-m+1;i<=n;i++) 13 ans=i%mod*ans%mod; 14 return (ans/mul)%MOD; 15 } 16 17 void dfs(L dep,L fu,L mi,L lim){ 18 if(dep==n+1){ 19 now=(now+fu*C(n+lim-mi,n)%MOD)%MOD; 20 return; 21 } 22 dfs(dep+1,fu,mi,lim); 23 dfs(dep+1,-fu,mi+m[dep]+1,lim); 24 } 25 L calc(L hh){ 26 now=0; 27 dfs(1,1,0,hh); 28 return now; 29 } 30 int main(){ 31 cin>>n>>a>>b; 32 mul=1; for(int i=2;i<=n;i++) mul*=i; 33 for(int i=1;i<=n;i++) cin>>m[i]; 34 ans=((calc(b)-calc(a-1))%MOD+MOD)%MOD; 35 cout<<ans<<endl; 36 }