题解 CF438E The Child and Binary Tree

$\texttt{link}$

题意

给定集合 $S=\{c_1,c_2,\cdots c_n\}$,求 $\forall{i\in\left[1,m\right]\cap\mathbb{N}}$,点权在给定 $S$ 内且点权和为 $i$ 的二叉树个数。

数据范围:$1\le n,m \le 10^5,1\le c_i\le10^5$

题解

令 $f_i$ 表示点权和为 $i$ 时的答案,$g_i=\left[i\in S\right]$。

有 DP 转移方程$$f_n=\begin{cases}1,n=0\\\sum\limits_{i=1}^n g_i\sum\limits_{j=0}^{n-i}f_jf_{n-i-j},n>0\end{cases}$$

可以理解为先枚举根节点的权值,再枚举左右子树的权值。

发现后半部分实质上是三个多项式卷起来后的系数,于是令 $F(x)$ 表示 $f$ 的生成函数,$G(x)$ 表示 $g$ 的生成函数。

可得$$F(x)=1+G(x)F^2(x)$$$$\Rightarrow G(x)F^2(x)-F(x)+1=0$$

由一元二次求根公式得

$$F(x)=\frac{-b\pm \sqrt{b^2-4ac}}{2a}=\frac{1\pm\sqrt{1-4G(x)}}{2G(x)}$$

发现有两个根,继续化简原式得$$2F(x)G(x)=1\pm\sqrt{1+4G(x)}$$ 当 $2F(x)G(x)=1+\sqrt{1+4G(x)}$ 时$$\because g_0=0$$$$\therefore \left[x^0\right]G(x)=0$$$$\therefore \left[x^0\right]2F(x)G(x)=0$$ 又$$\left[x^0\right]1+\sqrt{1-4G(x)}\ge1$$$$\therefore 2F(x)G(x)\ne1+\sqrt{1-4G(x)}$$ 故$$2F(x)G(x)=1-\sqrt{1-4G(x)}$$$$F(x)=\frac{1-\sqrt{1-4G(x)}}{2G(x)}$$$\left[x^0\right]G(x)=0$,无法求逆,考虑改变分子分母的形式。

分子分母同乘共轭根式 $1+\sqrt{1-4G(x)}$

$$F(x)=\frac{1-(1-4G(x))}{2G(x)(1+\sqrt{1-4G(x)})}$$$$F(x)=\frac{4G(x)}{2G(x)+2G(x)\sqrt{1-4G(x)}}$$$$F(x)=\frac{2}{1+\sqrt{1-4G(x)}}$$ 至此可以用多项式开根和多项式求逆求 $F(x)$。

#include <bits/stdc++.h>
using namespace std;
namespace IO {
    //read and write
} using namespace IO;
const int N = 2.7e5 + 10;
namespace Polynomial {
    const int P = 998244353, G = 3, Gi = 332748118, inv2 = 499122177;
    int lim, rev[N], a[N], b[N];
    int qpow(int n, int k) {
        int res = 1;
        for(; k; n = 1ll * n * n % P, k >>= 1)
            if(k & 1) res = 1ll * res * n % P;
        return res;
    }
    void NTT(int *f, int T) {
        for(int i = 0; i < lim; i++)
            if(i < rev[i]) 
                swap(f[i], f[rev[i]]);
        for(int mid = 1; mid < lim; mid <<= 1) {
            int wn = qpow(T == 1 ? G : Gi, (P - 1) / (mid << 1));
            int len = mid << 1;
            for(int i = 0; i < lim; i += (mid << 1)) {
                int w = 1;
                for(int j = 0; j < mid; j++, w = 1ll * w * wn % P) {
                    int x = f[i + j], y = 1ll * w * f[i + j + mid] % P;
                    f[i + j] = (x + y) % P;
                    f[i + j + mid] = (x - y + P) % P;
                }
            }
        }
        if(T == -1) {
            int inv = qpow(lim, P - 2);
            for(int i = 0; i < lim; i++) 
                f[i] = 1ll * f[i] * inv % P;
        }
    }
    void init(int n) {
        for(lim = 1; lim < n; lim <<= 1);
        for(int i = 0; i < lim; i++)
            rev[i] = (rev[i >> 1] >> 1) | ((i & 1) * (lim >> 1));
    } 
    void mul(int *f, int *g, int *h, int n, int m) {
        static int a[N], b[N];
        init(n + m - 1);
        memset(a, 0, lim << 2);
        memcpy(a, f, n << 2);
        memset(b, 0, lim << 2);
        memcpy(b, g, m << 2);
        NTT(a, 1), NTT(b, 1);
        for(int i = 0; i < lim; i++) 
            h[i] = 1ll * a[i] * b[i] % P;
        NTT(h, -1);
    }
    void inv(int *f, int *g, int n) {
        if(n == 1) { g[0] = qpow(f[0], P - 2); return; }
        inv(f, g, n + 1 >> 1);
        init(n << 1);
        copy(f, f + n, a);
        fill(a + n, a + lim, 0);
        NTT(a, 1), NTT(g, 1);
        for(int i = 0; i < lim; i++)
            g[i] = (2 - 1ll * a[i] * g[i] % P + P) % P * g[i] % P;
        NTT(g, -1);
        fill(g + n, g + lim, 0);
    }
    void sqrt(int *f, int *g, int n) {
        if(n == 1) { g[0] = 1; return; }
        sqrt(f, g, n + 1 >> 1);
        memset(b, 0, n << 2);
        inv(g, b, n);
        mul(f, b, b, n, n);
        for(int i = 0; i < n; i++)
            g[i] = 1ll * (g[i] + b[i]) * inv2 % P;
    }
}
using namespace Polynomial;
int n, m, maxn, f[N], g[N], h[N];
int main() {
    n = read(), m = read() + 1;
    f[0] = 1;
    for(int i = 1, x; i <= n; i++)
        x = read(), g[x] = 1, maxn = max(maxn, x);
    for(int i = 1; i <= maxn; i++)
        if(g[i]) g[i] = P - 4 * g[i];
    g[0]++;
    sqrt(g, h, m);
    h[0]++;
    inv(h, f, m);
    for(int i = 1; i < m; i++)
        write(2 * f[i] % P), putc('\n');
    flush();
    return 0;
}
posted @ 2021-08-05 14:03  Terac  阅读(11)  评论(0)    收藏  举报  来源