bzoj 3027: [Ceoi2004]Sweet (生成函数)

题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=3027

题目大意:有n种数,每种有Ci个,问你在这些数中取出[l,r]个,问你有多少种不同的取法,答案对2004取模。

数据范围:n10Ci1061l<r107

 

我们不妨设f(n)表示不超过n的数的取法之和。

则答案显然为f(r)f(l1),下面来推导f(x)。

显然,f(m)等于多项式Πni=1Cij=1xi[0,m]的系数和。

考虑到Ci很大,如果直接多项式乘法,会T,必须化简。

原式

=Πni=11xCi1x

=Πni=1(1xCi)(1x)n

=Πni=1(1xCi)j=1(n+jn1)x(j+1)

考虑式子的前半部分,不难发现,该部分最多只有2n个位置是非零的,显然我们只需要处理这部分,并不需要对整个多项式做乘法。实现该步骤一个dfs即可。

对于后半部分,假设求f(m)过程中前面通过dfs连乘出的单项式次数为k,系数为p,那么需要累加的答案显然多项式p×mk1j=1(n+jn1)x(j+1)

然后根据组合数的相关公式进行化简,得到p×(n+mk1n1)

然后就愉快地昨晚啦

 

复制代码
 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 @   AlphaInf  阅读(375)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示