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 }

 

 

 

 

 

posted @ 2018-05-19 09:09  AlphaInf  阅读(373)  评论(0编辑  收藏  举报