CF438E The Child and Binary Tree


Description

给一个大小为\(n\)的序列\(C\),保证\(C\)中每个元素各不相同,现在你要统计点权全在\(C\)中,且点权和为\(m\)的二叉树个数,并对\(998244353\)取模。

\(n,m \le 10^5\)

Solution

\(998244353\)?这很多项式......

总之先颓柿子好了。

令\(f_n\)表示权值和为\(n\)的二叉树个数,\(g_n\)表示权值\(n\)是否出现在\(C\)中。

那么枚举根节点的权值,然后在枚举左右儿子的权值和,即\((n>0)\)

\[f_n = \sum\limits_{i=1}^n g_i \sum\limits_{j=0}^{n-i} f_jf_{n-i-j}
\]

特别的\(f_0=1\)。

上面的柿子非常卷积吧!

令\(F(x) = \sum\limits_{n=0}^{\infty} f_nx^n,G(x) = \sum\limits_{n=0}^{\infty}g_nx^n\),那么

\[F(x) = G(x)F^2(x) + 1
\]

加一是因为\(f_0=1\)。

我们的目标就是把\(F(x)\)搞出来,先移项

\[G(x)F^2(x) - F(x) + 1 = 0
\]

然后解方程得到

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

有两个解,咋办? 对着样例各跑一遍

不慌,我们知道当\(x=0\)时,\(F(x)=1\)。

所以分类讨论一下

  • 取加号时,当\(x \to 0\),楼上分子会趋于\(1+1 = 2\),楼下分母会趋于\(0\),炸了......

  • 如果取减号,楼上楼下都会趋于\(0\),这是我们想要的。

所以

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

没了?

并没有......我们发现这个柿子还没有办法算出\(F\),因为\(2G\)可能是\(0\)。

我们取倒数再给他变一变,得到

\[F = \frac{2}{1+\sqrt{1-4G}}
\]

这样就非常\(nice\)。

因为我们只关心\(f_1...f_m\),所以在\(mod \ x^{m+1}\)的意义下开根求逆就好了。

#include <bits/stdc++.h>
using namespace std;
const int N=3e5+10,P=998244353,gen=3,igen=(P+1)/gen;
inline int add(int x,int y){
return x+y>=P?x+y-P:x+y;
}
inline int sub(int x,int y){
return x-y<0?x-y+P:x-y;
}
inline int fpow(int x,int y){
int ret=1; for (x%=P;y;y>>=1,x=1ll*x*x%P)
if (y&1) ret=1ll*ret*x%P;
return ret;
}
inline int sqr(int x){
return 1ll*x*x%P;
}
namespace Poly{
int rev[N];
void init(int n){
for (int i=0;i<n;i++)
rev[i]=rev[i>>1]>>1|((i&1)?n>>1:0);
}
void ntt(int *f,int n,int flg){
for (int i=0;i<n;i++) if (rev[i]<i) swap(f[i],f[rev[i]]);
for (int k=1,len=2;len<=n;len<<=1,k<<=1){
int wn=fpow(flg==1?gen:igen,(P-1)/len);
for (int i=0;i<n;i+=len){
for (int w=1,j=i;j<i+k;j++,w=1ll*w*wn%P){
int tmp=1ll*w*f[j+k]%P;
f[j+k]=sub(f[j],tmp),f[j]=add(f[j],tmp);
}
}
}
if (flg==-1){
int inv=fpow(n,P-2);
for (int i=0;i<n;i++) f[i]=1ll*f[i]*inv%P;
}
}
void getinv(int *f,int n,int *G){
if (n==1){G[0]=fpow(f[0],P-2);return;}
getinv(f,(n+1)>>1,G); static int F[N];
int limit=1; while(limit<=2*n)limit<<=1; init(limit);
for (int i=0;i<limit;i++) F[i]=i>=n?0:f[i],G[i]=i>=n?0:G[i];
ntt(F,limit,1),ntt(G,limit,1);
for (int i=0;i<limit;i++) G[i]=1ll*G[i]*sub(2,1ll*F[i]*G[i]%P)%P;
ntt(G,limit,-1);
for (int i=n;i<limit;i++) G[i]=0;
}
void getsqrt(int *f,int n,int *G){
if (n==1){G[0]=1;return;}
getsqrt(f,(n+1)>>1,G);
int limit=1; while(limit<=n*2)limit<<=1; init(limit);
static int F[N],H[N],iH[N];
for (int i=0;i<limit;i++)
G[i]=i>=n?0:G[i],F[i]=i>=n?0:f[i],H[i]=i>=n?0:2ll*G[i]%P;
getinv(H,n,iH);
ntt(F,limit,1),ntt(iH,limit,1),ntt(G,limit,1);
for (int i=0;i<limit;i++) G[i]=1ll*add(F[i],sqr(G[i]))*iH[i]%P;
ntt(G,limit,-1);
for (int i=n;i<limit;i++) G[i]=0;
}
}
int n,m,g[N],f[N],sqg[N];
int main(){
scanf("%d%d",&n,&m);
for (int i=0,c;i<n;i++) scanf("%d",&c),g[c]=1;
for (int i=1;i<=m;i++) g[i]=sub(P,4ll*g[i]%P);
g[0]=1;
Poly::getsqrt(g,m+1,sqg);
sqg[0]++;
Poly::getinv(sqg,m+1,f);
for (int i=1;i<=m;i++) printf("%d\n",2ll*f[i]%P);
return 0;
}

[题解] CF438E The Child and Binary Tree的更多相关文章

  1. 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( ...

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

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

  3. CF438E The Child and Binary Tree

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

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

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

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

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

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

    [CF438E]The Child and Binary Tree(多项式运算,生成函数) 题面 有一个大小为\(n\)的集合\(S\) 问所有点权都在集合中,并且点权之和分别为\([0,m]\)的二 ...

  7. [codeforces438E]The Child and Binary Tree

    [codeforces438E]The Child and Binary Tree 试题描述 Our child likes computer science very much, especiall ...

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

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

  9. 【题解二连发】Construct Binary Tree from Inorder and Postorder Traversal & Construct Binary Tree from Preorder and Inorder Traversal

    LeetCode 原题链接 Construct Binary Tree from Inorder and Postorder Traversal - LeetCode Construct Binary ...

随机推荐

  1. 8051单片机中访问int中字节的方法

    在使用单片机中,unsigned int 占2个字节,unsigned char 占一个字节.而单片机是实行的字节寻址.16字节的bit寻址实在是不好用, 不好用在不能建数组. 在实际的开发过程中,要 ...

  2. 51nod 1099:任务执行顺序 贪心

    1099 任务执行顺序 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题  收藏  取消关注 有N个任务需要执行,第i个任务计算时占R[i]个空间,而后会释放一部分, ...

  3. ROS学习笔记3-基础课程之文件系统向导

    准备工作需要使用如下命令安装ros的教程: $ sudo apt-get install ros-<distro>-ros-tutorials 其中,distro为所用ros的发行版本,该 ...

  4. 【WPF学习】第二十二章 文本控件

    WPF提供了三个用于输入文本的控件:TextBox.RichTextBox和PasswordBox.PasswordBox控件直接继承自Control类.TextBox和RichTextBox控件间接 ...

  5. python反序列化漏洞

    原理在网页源码中如果出现将用户输入数据进行反序列化当成参数输出时,出现漏洞,可造成任意命令执行例如网页源码try:       become = self.get_argument('become') ...

  6. 记号一下用iptables做的端口转发

    iptables -t nat -I PREROUTING -p tcp -m tcp --dport 83 -j DNAT --to-destination 192.168.1.55:443ipta ...

  7. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-chevron-right

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...

  8. python三大神器===》生成器

    1. 认识生成器 利用迭代器,我们可以在每次迭代获取数据(通过next()方法)时按照特定的规律进行生成.但是我们在实现一个迭代器时,关于当前迭代到的状态需要我们自己记录,进而才能根据当前状态生成下一 ...

  9. DEDECMS打开网站后台系统首页卡解决方法

    找到根目录下(一般是dede) templets文件夹下找到index_body.htm文件,将第25行至第41行部分注释或删除 保存文件,然后再打开后台,就不会有这个问题了.

  10. SQL语句--分组统计

    一.教师号 星期号 是否有课1 2 有1 3 有2 1 有3 2 有`1 2 有写一条sql语句让你变为这样的表教师号 星期一 星期二 星期三1 2 12 13 1各星期下的数字表示:对应的教师在星期 ...