Loading

【题解】CF438E The Child and Binary Tree

数学不好,大概率是不严谨的。

思路

生成函数 + 卷积。

首先意识到值域是 \(10^5\),似乎可以搞事情。并且此题还是对 \(998244353\) 取模的数树题,可以考虑生成函数。

首先令 \(f_n\) 表示合法且权值为 \(n\) 的二叉树个数。

考虑钦定树根的值,可以枚举左右子树的权值和转移:

\(f_n = \sum\limits_{i = 1}^n [i \in c] \sum\limits_{j = 1}^{n - i} f_j \cdot f_{n - i - j}\).

边界条件是 \(f_0 = 1\),即空树。

对于 \([i \in c]\),可以考虑令它等于 \(g_i\).

\(F\)\(f\) 的生成函数,\(G\)\(g\) 的生成函数。

考虑上式的形式,发现实际上是三个多项式的卷积,也就是 \(G * F^2\).

所以原式等价于 \(F = G * F^2 + 1\).

一元二次方程求根公式得 \(F = \frac{1 \pm \sqrt{1 - 4G}}{2G}\).

然而注意到权值都是整数,所以 \(G\) 的零次项为 \(0\),导致 \(G\) 不能做多项式开根。

所以考虑分子有理化成 \(\frac{2}{1 \pm \sqrt{1 - 4G}}\).

注意到 \(\lim\limits_{x \rightarrow 0} \sqrt{1 - 4G} = \sqrt{1 - 4 \cdot [x^0] G(x)} = 1\).

所以取正时 \(\lim\limits_{x \rightarrow 0} \frac{2}{1 \pm \sqrt{1 - 4G}} = 1\),反之分母会出问题。

所以取正,然后多项式求逆 + 开根就行。

这里有神仙指出在形式幂级数意义下 \(G\) 不可求逆,不太懂,有懂哥可以教一下吗 /kk

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long ll;

const int sz = 3e5 + 5;
const int mod = 998244353;
const int g = 3;

int n, m;
int c[sz], rev[sz];
ll G[sz], inv[sz], tmp[sz], sq[sz], wp[sz];
ll Ft[sz], Rt[sz], ft[sz], rt[sz];

void calc_rev(int k) { for (int i = 1; i < k; i++) rev[i] = (rev[i >> 1] >> 1 | (i & 1 ? k >> 1 : 0)); }

ll qpow(ll base, ll power, ll mod)
{
    ll res = 1;
    while (power)
    {
        if (power & 1) res = res * base % mod;
        base = base * base % mod;
        power >>= 1;
    }
    return res;
}

void NTT(ll *A, int n)
{
    calc_rev(n);
    for (int i = 1; i < n; i++)
        if (rev[i] > i) swap(A[i], A[rev[i]]);
    for (int len = 2, m = 1; len <= n; m = len, len <<= 1)
    {
        ll wn = qpow(g, (mod - 1) / len, mod);
        wp[0] = 1;
        for (int i = 1; i <= len; i++) wp[i] = wp[i - 1] * wn % mod;
        for (int l = 0, r = len - 1; r <= n; l += len, r += len)
        {
            int w = 0;
            for (int p = l; p < l + m; p++, w++)
            {
                ll x = A[p], y = wp[w] * A[p + m] % mod;
                A[p] = (x + y) % mod, A[p + m] = (x - y + mod) % mod;
            }
        }
    }
}

void INTT(ll *A, int n)
{
    NTT(A, n);
    reverse(A + 1, A + n);
    int inv = qpow(n, mod - 2, mod);
    for (int i = 0; i < n; i++) A[i] = 1ll * A[i] * inv % mod;
}

void invp(ll *f, ll *r, int n)
{
    int k = 1;
    while (k < n) k <<= 1;
    r[0] = qpow(f[0], mod - 2, mod);
    for (int len = 2, m = 1; len <= k; m = len, len <<= 1)
    {
        for (int i = 0; i < len; i++) Rt[i] = r[i], Ft[i] = f[i];
        NTT(Ft, len), NTT(Rt, len);
        for (int i = 0; i < len; i++) Rt[i] = Rt[i] * Ft[i] % mod;
        INTT(Rt, len);
        for (int i = 0; i < m; i++) Rt[i] = 0; Rt[0] = 1;
        for (int i = 0; i < len; i++) Ft[i] = r[i];
        NTT(Ft, len), NTT(Rt, len);
        for (int i = 0; i < len; i++) Rt[i] = Rt[i] * Ft[i] % mod;
        INTT(Rt, len);
        for (int i = m; i < len; i++) r[i] = (r[i] * 2ll - Rt[i] + mod) % mod;
    }
    memset(Ft, 0, k * sizeof(ll));
    memset(Rt, 0, k * sizeof(ll));
    for (int i = n; i < k; i++) r[i] = 0;
}

void sqrtp(ll *f, ll *s, int n)
{
    s[0] = 1;
    int k = 1;
    while (k < (n << 1)) k <<= 1;
    ll inv2 = qpow(2, mod - 2, mod);
    for (int len = 2, m = 1; len <= k; m = len, len <<= 1)
    {
        invp(s, rt, m);
        for (int i = 0; i < m; i++) ft[i] = f[i];
        NTT(ft, len), NTT(rt, len);
        for (int i = 0; i < len; i++) rt[i] = rt[i] * ft[i] % mod;
        INTT(rt, len);
        for (int i = 0; i < m; i++) rt[i] = (rt[i] + s[i]) % mod;
        for (int i = 0; i < len; i++) s[i] = rt[i] * inv2 % mod, rt[i] = ft[i] = 0;
    }
    for (int i = 0; i < k; i++) rt[i] = ft[i] = 0;
    for (int i = n; i < k; i++) s[i] = 0;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%d", &c[i]), G[c[i]] = 1;
    tmp[0] = 1; for (int i = 1; i <= m; i++) tmp[i] = mod - 4 * G[i] % mod;
    sqrtp(tmp, sq, m + 1);
    sq[0]++;
    invp(sq, inv, m + 1);
    for (int i = 1; i <= m; i++) inv[i] = 2ll * inv[i] % mod;
    for (int i = 1; i <= m; i++) printf("%lld\n", inv[i]);
    return 0;
}
posted @ 2023-02-02 16:58  kymru  阅读(18)  评论(0编辑  收藏  举报