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. PAT (Advanced Level) 1124~1127:1124模拟 1125优先队列 1126欧拉通路 1127中序后序求Z字形层序遍历

    1124 Raffle for Weibo Followers(20 分) 题意:微博抽奖,有M个人,标号为1~M.从第S个人开始,每N个人可以获奖,但是已获奖的人不能重复获奖,需要跳过该人把机会留给 ...

  2. HomePod即将发售,但硬件不再是苹果的救命稻草

    流年不利的苹果,在多个维度都遭到了重创.除了与高通纠缠不清的专利官司外,iPhone销量还直线下滑并影响到营收.最终,苹果股价.市值都处于暴跌态势.面对内外夹击的不利局面,苹果信奉多年的"封 ...

  3. B. Yet Another Crosses Problem

    B. Yet Another Crosses Problem time limit per test 2 seconds memory limit per test 256 megabytes inp ...

  4. websocket与http

    偶然在知乎上看到一篇回帖,瞬间觉得之前看的那么多资料都不及这一篇回帖让我对 websocket 的认识深刻有木有.所以转到我博客里,分享一下.比较喜欢看这种博客,读起来很轻松,不枯燥,没有布道师的阵仗 ...

  5. Linux下的文件目录树结构

    Linux下的文件目录及文件结构 一.文件和文件夹 在Linux系统下,一切皆是文件.就连Linux本身也是基于文件表示的操作系统. 1.文件:文件在Linux系统之下,一般分为两种:一是一般性文件, ...

  6. cf 762D. Maximum path

    天呢,好神奇的一个DP23333%%%%% 因为1.向左走1格的话相当于当前列和向左走列全选 2.想做走超过1的话可以有上下走替代.而且只能在相邻行向左. 全选的情况只能从第1行和第3行转移,相反全选 ...

  7. tf.argmax()函数作用

    tf.argmax()函数原型: def argmax(input, axis=None, name=None, dimension=None, output_type=dtypes.int64) 作 ...

  8. 046-unset对静态变量无法销毁

    <?php function digui() { static $count = 0; echo $count; $count++; unset($count); } digui(); digu ...

  9. opencv+python实时人脸检测、磨皮

    import numpy as np import cv2 cap = cv2.VideoCapture(0) face_cascade = cv2.CascadeClassifier("d ...

  10. python 网页爬虫 基础篇

    首先要连接自己的数据库 import pymysql import requests #需要导入模块 db = pymysql.connect('localhost', 'root', '****** ...