生成函数入门
EnofTaiPeople · · 题解
Part1 前言
什么?我只会数据结构?不会生成函数怎么办啊!
虽然多项式已经“滚出 NOI”了,但它很有利于理解生成函数,毕竟考试要是正解生成函数只是放暴力卷积过呢?
Part2 形式及含义
给定数列
对于数列
它的指数生成函数为
Part3 问题转化
对于这类题,我们可以先想一想能否得到与答案类似的东西。
比如,设
但这并不是我们想要得到的答案,设
到了这一步,生成函数的作用就在于构建卷积关系,当然我们需要让函数的项只与次数相关。
将二项式拆开,得到
设
那么
Part4 另一个角度
上面只是用来发掘指数与计数的联系,其实普通生成函数也可以,甚至不用对数,毕竟对数的实现也是多项式求逆。
事实上,设
那么有
Part5 后记
怎么会告一段落,生成函数远不只这些,当然可以放代码:
方法一:
int main(){
ios::sync_with_stdio(false);
int i,j,k,l,r,x,y;
cin>>n;
jc[0]=nv[0]=nv[1]=1;
for(x=2;x<=n;++x)nv[x]=ll(M-M/x)*nv[M%x]%M;
for(x=1;x<=n;++x){
jc[x]=ll(jc[x-1])*x%M;
nv[x]=ll(nv[x-1])*nv[x]%M;
}
for(x=0;x<=n;++x)g[x]=ll(qp(2,ll(x-1)*x/2%(M-1)))*nv[x]%M;
P.Ln(g,f,18);
k=ll(f[n])*jc[n]%M;
printf("%d\n",k);
return 0;
}
方法二:
int main(){
ios::sync_with_stdio(false);
int i,j,k,l,r,x,y;
cin>>n;
jc[0]=nv[0]=nv[1]=1;
for(x=2;x<=n;++x)nv[x]=ll(M-M/x)*nv[M%x]%M;
for(x=1;x<=n;++x){
jc[x]=ll(jc[x-1])*x%M;
nv[x]=ll(nv[x-1])*nv[x]%M;
}
for(x=0;x<=n;++x)g[x]=ll(qp(2,ll(x-1)*x/2%(M-1)))*nv[x]%M;
P.Inv(g,f,18);
memset(g,0,4<<19);
for(x=1;x<=n;++x)g[x]=ll(qp(2,ll(x-1)*x/2%(M-1)))*nv[x-1]%M;
P.mul(f,g);
k=ll(f[n])*jc[n-1]%M;
printf("%d\n",k);
return 0;
}