CF438E The Child and Binary Tree

题目

生成函数就是好,什么题目都能搞

先来列一个暴力\(dp\),\(dp_i\)表示形成\(i\)点权的二叉树的方案数

我们可以直接列出方程

\[
dp_i=\sum_{k=1}^n\sum_{j=0}^{i-c_k}dp_jdp_{i-c_k-j}
\]

边界条件\(dp_0=1\)

发现里面类似卷积,于是生成函数来搞

\[
F(x)=\sum_{i=0}([i=0]+\sum_{k=1}^n\sum_{j=0}^{i-c_k}dp_jdp_{i-c_k-j})x^i
\]

\[
F(x)=1+\sum_{k=1}^nx^{c_k}\sum_{j=0}^{i-c_k}dp_jx^j\times dp_{i-c_k-j}x^{i-c_k-j}
\]

发现里面就是\(F^2(x)\),于是

\[
F(x)=1+\sum_{k=1}^nx^{c_k}F^2(x)
\]

发现有一个乘以\(x^{c_k}\)之后再求和,设那个多项式为\(G(x)\),不就是卷上那边的那个多项式吗

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

于是我们可以解方程了

发现

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

发现取正不收敛,于是

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

于是我们多项式求逆+多项式开根就能搞了

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=262144+1005;
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const LL mod=998244353;
const LL G[2]={3,332748118};
LL A[maxn],B[maxn],C[maxn],K[maxn],D[maxn],H[maxn],T[maxn],F[maxn];
LL a[maxn],b[maxn];
int n,m,rev[maxn],len;
inline LL ksm(LL a,int b) {LL S=1;while(b){if(b&1) S=S*a%mod;b>>=1;a=a*a%mod;}return S;}
inline void NTT(LL *f,int o) {
    for(re int i=0;i<len;i++) if(i<rev[i]) std::swap(f[i],f[rev[i]]);
    for(re int i=2;i<=len;i<<=1) {
        int ln=i>>1;LL og1=ksm(G[o],(mod-1)/i);
        for(re int l=0;l<len;l+=i) {
            LL t,og=1;
            for(re int x=l;x<l+ln;x++) {
                t=(og*f[ln+x])%mod;
                f[ln+x]=(f[x]-t+mod)%mod;
                f[x]=(f[x]+t)%mod;
                og=(og*og1)%mod;
            }
        }
    }
    if(!o) return;
    LL inv=ksm(len,mod-2);
    for(re int i=0;i<len;i++) f[i]=(f[i]*inv)%mod;
}
inline void mul(LL *A,LL *B,int n) {
    len=1;while(len<n+n) len<<=1;
    for(re int i=0;i<len;i++) rev[i]=rev[i>>1]>>1|((i&1)?len>>1:0);
    NTT(A,0),NTT(B,0);
    for(re int i=0;i<len;i++) A[i]=(A[i]*B[i])%mod;
    NTT(A,1);for(re int i=n;i<len;i++) A[i]=0;
}
inline void Inv(int n,LL *A,LL *B) {
    if(n==1) {B[0]=ksm(A[0],mod-2);return;}
    Inv((n+1)>>1,A,B);
    memset(C,0,sizeof(C));memset(K,0,sizeof(K)),memset(D,0,sizeof(D));
    for(re int i=0;i<n;i++) C[i]=A[i],D[i]=K[i]=B[i];
    mul(K,C,n);mul(K,D,n);
    for(re int i=0;i<n;i++) B[i]=(2ll*B[i]-K[i]+mod)%mod;
}
inline void Sqrt(int n,LL *A,LL *B) {
    if(n==1) {B[0]=1;return;}
    Sqrt((n+1)>>1,A,B);
    memset(H,0,sizeof(H));memset(F,0,sizeof(F));memset(T,0,sizeof(T));
    for(re int i=0;i<n;i++) F[i]=B[i],T[i]=2ll*B[i];
    Inv(n,T,H);mul(B,F,n);
    for(re int i=0;i<n;i++) B[i]=(B[i]+A[i])%mod;
    mul(B,H,n);
}
int main() {
    n=read(),m=read();
    for(re int i=1;i<=n;i++) a[read()]+=4;
    for(re int i=0;i<=m;i++) a[i]=mod-a[i],a[i]%=mod;
    a[0]++;Sqrt(m+1,a,A);A[0]++;Inv(m+1,A,b);
    for(re int i=1;i<=m;i++) printf("%lld\n",2ll*b[i]%mod);
    return 0;
}

原文地址:https://www.cnblogs.com/asuldb/p/10546568.html

时间: 2024-10-09 07:21:45

CF438E The Child and Binary Tree的相关文章

CF438E The Child and Binary Tree——生成函数

题面 CF438E 解析 一开始又把题读错了... 设$g_i=1/0$表示数$i$是否在$c$中出现过,$f_i$表示权值和为$i$的二叉树个数,有下式:$$f_i=\sum_{j=1}^{m}g_j\sum_{k=0}^{i-j}f_k f_{i-j-k}$$ 设$F(x)=\sum_{i=0}^{\infty}f_i x^i$, $G(x)=\sum_{i=0}^{\infty}g_i x^i$,有:$$F=G*F^2 + 1$$ 后面$+1$是因为$g_0=0$而$f_0=1$ 求根公式

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

传送门 可以……这很多项式开根模板……而且也完全不知道大佬们怎么把这题的式子推出来的…… 首先,这题需要多项式开根和多项式求逆.多项式求逆看这里->这里,这里讲一讲多项式开根 多项式开方:已知多项式$A$,求多项式$B$满足$A^2\equiv B\pmod{x^n}$(和多项式求逆一样这里需要取模,否则$A$可能会有无数项) 假设我们已经求出$A'^2\equiv B\pmod{x^n}$,考虑如何计算出$A^2\equiv B\pmod{x^{2n}}$ 首先肯定存在$A^2\equiv B

cf438E. The Child and Binary Tree(NTT 多项式开根 多项式求逆)

题意 链接 Sol 生成函数博大精深Orz 我们设\(f(i)\)表示权值为\(i\)的二叉树数量,转移的时候可以枚举一下根节点 \(f(n) = \sum_{w \in C_1 \dots C_n} \sum_{j=0}^{n-w} f(j) f(n-w-j)\) 设\(T =n-w\),后半部分变为\(\sum_{j=0}^T f(j) f(T-j)\),是个标准的卷积形式. 对于第一重循环我们可以设出现过的数的生成函数\(C(x)\) 可以得到\(f = C * f * f + 1\),+

codeforces #250E The Child and Binary Tree 快速傅里叶变换

题目大意:给定一个集合S,对于i=1...m求有多少二叉树满足每个节点的权值都在集合S中且权值和为i 构造答案多项式F(x)和集合S的生成函数C(x),那么 根节点的左子树是一棵二叉树,右子树是一棵二叉树,本身的权值必须在集合S中,此外还有空树的情况 故有F(x)=F2(x)C(x)+1 解得F(x)=1±1?4C(x)√2C(x)=21±1?4C(x)√ 若等式下方取减号则分母不可逆,舍去 得到F(x)=21+1?4C(x)√ 有关多项式求逆和多项式开根的内容参见Picks的博客 CF上每个点

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 开方:https://blog.csdn.net/kscla/article/details/79356786 不过还是不会二次剩余. 也不知道为什么取了 G(x)-B(x)=0 而不是 G(x)+B(x)=0. 式子是  B(x) = ( A(x) + G2(x) ) / 2*G(x) ,但写的

LeetCode Binary Tree Inorder Traversal

LeetCode解题之Binary Tree Inorder Traversal 原题 不用递归来实现树的中序遍历. 注意点: 无 例子: 输入: {1,#,2,3} 1 2 / 3 输出: [1,3,2] 解题思路 通过栈来实现,从根节点开始,不断寻找左节点,并把这些节点依次压入栈内,只有在该节点没有左节点或者它的左子树都已经遍历完成后,它才会从栈内弹出,这时候访问该节点,并它的右节点当做新的根节点一样不断遍历. AC源码 # Definition for a binary tree node

Binary Tree Longest Consecutive Sequence

Given a binary tree, find the length of the longest consecutive sequence path. The path refers to any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The longest consecutive path need to be from p

leetCode(42):Flatten Binary Tree to Linked List

Given a binary tree, flatten it to a linked list in-place. For example, Given 1 / 2 5 / \ 3 4 6 The flattened tree should look like: 1 2 3 4 5 6 If you notice carefully in the flattened tree, each node's right child points to the next node of a pre-o

[LeetCode] Binary Tree Upside Down

Problem Description: Given a binary tree where all the right nodes are either leaf nodes with a sibling (a left node that shares the same parent node) or empty, flip it upside down and turn it into a tree where the original right nodes turned into le