【CF438E】The Child and Binary Tree(多项式运算,生成函数)

题面

有一个大小为\(n\)的集合\(S\)

问所有点权都在集合中,并且点权之和分别为\([0,m]\)的二叉树的个数。

\(n,m<=10^5\)

题解

设\(f(i)\)表示点权和为\(i\)的二叉树个数,\(c(i)\)是集合中数的生成函数,那么我们可以得到

\[f(n)=\sum_{i=1}^{n}c(i)\sum_{j=0}^{n-i}f(j)f(n-i-j)
\]

显然有\(f(0)=1\)

构造生成函数\(F(x)=\sum_{i=0}^{\infty}f(i)x^i,C(x)=\sum_{i=0}^{\infty}c(i)x^i\)。回顾递推式,后面的显然是\(F(x)*F(x)\),而如果设\(G(x)=F(x)*F(x)\)

那么,根据上面的式子\([x^n]F(n)=\sum_{i=0}^{n}c(i)[x^n]G(n-i)\)

所以,\(F(x)=G(x)*C(x)+1=F(x)*F(x)*C(x)+1\),要\(+1\)的原因是,如果只算卷积,我们会漏算\(f(0)=1\)。直接解方程就行了。

\[F(x)=\frac{2}{1+\sqrt{1-4C(x)}}
\]

负号被舍去的原因是,生成函数的\(x\)没有实际意义,因此可以带入任何数,当带入\(x=0\)时,分母为\(0\),所以底下为正号。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 500000
#define MOD 998244353
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int n,m,inv2,d[MAX];
int fpow(int a,int b)
{
int s=1;
while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
return s;
}
namespace NTT
{
int r[MAX],N,M,l;
int A[MAX],B[MAX];
void NTT(int *P,int n,int opt)
{
int N=1,l=0;for(N=1;N<n;N<<=1)++l;
for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=1;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]);
for(int i=1;i<N;i<<=1)
{
int W=fpow(3,(MOD-1)/(i<<1));
for(int p=i<<1,j=0;j<N;j+=p)
{
int w=1;
for(int k=0;k<i;++k,w=1ll*w*W%MOD)
{
int X=P[j+k],Y=P[i+j+k]*1ll*w%MOD;
P[j+k]=(X+Y)%MOD;P[i+j+k]=(X-Y+MOD)%MOD;
}
}
}
if(opt==-1)
{
reverse(&P[1],&P[N]);
for(int i=0,inv=fpow(N,MOD-2);i<N;++i)P[i]=1ll*P[i]*inv%MOD;
}
}
}
int b[MAX];
int A[MAX],B[MAX],C[MAX],D[MAX],c[MAX];
void Inv(int *a,int *b,int len)
{
if(len==1){b[0]=fpow(a[0],MOD-2);return;}
Inv(a,b,len>>1);
for(int i=0;i<len;++i)A[i]=a[i],B[i]=b[i];
NTT::NTT(A,len<<1,1);NTT::NTT(B,len<<1,1);
for(int i=0;i<(len<<1);++i)A[i]=1ll*A[i]*B[i]%MOD*B[i]%MOD;
NTT::NTT(A,len<<1,-1);
for(int i=0;i<len;++i)b[i]=(b[i]+b[i])%MOD;
for(int i=0;i<len;++i)b[i]=(b[i]+MOD-A[i])%MOD;
for(int i=0;i<(len<<1);++i)A[i]=B[i]=0;
}
void Sqrt(int *a,int *b,int len)
{
if(len==1){b[0]=a[0];return;}
Sqrt(a,b,len>>1);
for(int i=0;i<=len;++i)C[i]=a[i];
Inv(b,D,len);
NTT::NTT(C,len<<1,1);NTT::NTT(D,len<<1,1);
for(int i=0;i<(len<<1);++i)D[i]=1ll*D[i]*C[i]%MOD;
NTT::NTT(D,len<<1,-1);
for(int i=0;i<len;++i)b[i]=1ll*(D[i]+b[i])%MOD*inv2%MOD;
for(int i=0;i<=(len<<1);++i)C[i]=D[i]=0;
}
int main()
{
n=read();m=read();inv2=fpow(2,MOD-2);
for(int i=1;i<=n;++i)++d[read()];
int N=1;while(N<=m)N<<=1;
for(int i=0;i<N;++i)d[i]=(-4*d[i]+MOD)%MOD;
++d[0];
Sqrt(d,c,N);
for(int i=0;i<N;++i)d[i]=0;
c[0]=(c[0]+1)%MOD;
Inv(c,d,N);
for(int i=0;i<=m;++i)d[i]=(d[i]+d[i])%MOD;
for(int i=1;i<=m;++i)printf("%d\n",d[i]);
return 0; }

【CF438E】The Child and Binary Tree(多项式运算,生成函数)的更多相关文章

  1. [题解] CF438E The Child and Binary Tree

    CF438E The Child and Binary Tree Description 给一个大小为\(n\)的序列\(C\),保证\(C\)中每个元素各不相同,现在你要统计点权全在\(C\)中,且 ...

  2. Codeforces 250 E. The Child and Binary Tree [多项式开根 生成函数]

    CF Round250 E. The Child and Binary Tree 题意:n种权值集合C, 求点权值和为1...m的二叉树的个数, 形态不同的二叉树不同. 也就是说:不带标号,孩子有序 ...

  3. Codeforces 438E. The Child and Binary Tree 多项式,FFT

    原文链接www.cnblogs.com/zhouzhendong/p/CF438E.html 前言 没做过多项式题,来一道入门题试试刀. 题解 设 $a_i$ 表示节点权值和为 $i$ 的二叉树个数, ...

  4. cf438E. The Child and Binary Tree(生成函数 多项式开根 多项式求逆)

    题意 链接 Sol 生成函数博大精深Orz 我们设\(f(i)\)表示权值为\(i\)的二叉树数量,转移的时候可以枚举一下根节点 \(f(n) = \sum_{w \in C_1 \dots C_n} ...

  5. CF438E The Child and Binary Tree(生成函数+多项式开根+多项式求逆)

    传送门 可以……这很多项式开根模板……而且也完全不知道大佬们怎么把这题的式子推出来的…… 首先,这题需要多项式开根和多项式求逆.多项式求逆看这里->这里,这里讲一讲多项式开根 多项式开方:已知多 ...

  6. CF438E The Child and Binary Tree 生成函数、多项式开根

    传送门 设生成函数\(C(x) = \sum\limits_{i=0}^\infty [\exists c_j = i]x^i\),答案数组为\(f_1 , f_2 , ..., f_m\),\(F( ...

  7. CF438E The Child and Binary Tree

    思路 设F(x)的第x项系数为权值和为x的答案 题目中要求权值必须在集合中出现,这个不好处理,考虑再设一个C,C的第x项如果是1代表x出现在值域里,如果是0,代表x没有出现在值域里,然后由于二叉树可以 ...

  8. CF438E The Child and Binary Tree(生成函数,NTT)

    题目链接:洛谷 CF原网 题目大意:有 $n$ 个互不相同的正整数 $c_i$.问对于每一个 $1\le i\le m$,有多少个不同形态(考虑结构和点权)的二叉树满足每个点权都在 $c$ 中出现过, ...

  9. bzoj 3625(CF 438E)The Child and Binary Tree——多项式开方

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3625 http://codeforces.com/contest/438/problem/E ...

  10. Codeforces 438E The Child and Binary Tree [DP,生成函数,NTT]

    洛谷 Codeforces 思路 看到计数和\(998244353\),可以感觉到这是一个DP+生成函数+NTT的题. 设\(s_i\)表示\(i\)是否在集合中,\(A\)为\(s\)的生成函数,即 ...

随机推荐

  1. idea热部署时 编写Controller会接收不到参数

    因为我是热部署启动服务器后才编写的request和getparameter 所以可能接收不到 重启一下服务器即可

  2. cookie,session傻傻分不清楚?

    做了这么多年测试,还是分不清什么是cookie,什么是session?很正常,很多初级开发工程师可能到现在都搞不清什么是session,cookie相对来说会简单很多. 下面这篇文章希望能够帮助大家分 ...

  3. [转]50 Tips for Working with Unity (Best Practices)

    About these tips These tips are not all applicable to every project. They are based on my experience ...

  4. Linux系统服务(daemon)(鸟哥Linux私房菜笔记)

    Linux系统服务(daemon) 一.SystemV的init管理机制(脚本式启动)1.服务启动分类stand alone 独立启动模式super daemon 总管程序 2.服务的启动.关闭与观察 ...

  5. Java基础知识:Java实现Map集合二级联动2

    2. 定义获取省份的方法,创建一个Map集合,将上一步得到的映射集合赋值给它,使用Map集合的keySet()方法获取该集合中的所有键对象组成的Set 集合,即为省分集合,创建一个Object型一维数 ...

  6. Ubuntu—安装python的第三方包gevent

    今晚花很多时间, 使用 sudo pip3 install gevent 但是始终没有成功. 柳暗花明又一村 sudo apt-get install python3-gevent 搞定!!! 人生如 ...

  7. Alpha阶段第2周/共2周 Scrum立会报告+燃尽图 03

    此次作业要求参见https://edu.cnblogs.com/campus/nenu/2018fall/homework/2286 Scrum master:范洪达 一.小组介绍 组长:王一可 组员 ...

  8. Swift-setValuesForKeysWithDictionary

    重写 setValuesForKeysWithDictionary 那么字典中可以有的字段在类中没有对应属性 class Person : NSObject { var age :Int = // 重 ...

  9. 【week11】psp

    本周psp 项目 内容 开始时间 结束时间 被打断 净时间 11.26(星期六)  看论文 psiBlast  9:00 12:00  5  175    11.28(星期一)  做作业 设计模式作业 ...

  10. (十二)Jmeter之Bean Shell的使用(一)

    一.什么是Bean Shell BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法; BeanShell是一种松散类型的脚本语言(这点和JS类似); BeanS ...