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

Posted joker-yza

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF438E The Child and Binary Tree——生成函数相关的知识,希望对你有一定的参考价值。

题面

  CF438E

解析

  一开始又把题读错了...

  设$g_i=1/0$表示数$i$是否在$c$中出现过,$f_i$表示权值和为$i$的二叉树个数,有下式:$$f_i=sum_{j=1}^{m}g_jsum_{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$

  求根公式:$$F = frac{1 pm sqrt{1-4G}}{2G} \ F=frac{2}{1pm sqrt{1-4G}}$$

  取$+$号:$lim_{x o 0}F(x)=1$,符合题意

  取$-$号:$lim_{x o 0}F(x)=infty$,不符题意,舍去  

  故:$$F=frac{2}{1 + sqrt{1-4G}}$$

  多项式开根+多项式求逆

   $O(N log N)$

 代码:

技术图片
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn = 200005, mod = 998244353, g = 3;

inline int read()
{
    int ret, f=1;
    char c;
    while((c=getchar())&&(c<0||c>9))if(c==-)f=-1;
    ret=c-0;
    while((c=getchar())&&(c>=0&&c<=9))ret=(ret<<3)+(ret<<1)+c-0;
    return ret*f;
}

int add(int x, int y)
{
    return x + y < mod? x + y: x + y - mod;
}

int rdc(int x, int y)
{
    return x - y < 0? x - y + mod: x - y;
}

ll qpow(ll x, int y)
{
    ll ret = 1;
    while(y)
    {
        if(y&1)
            ret = ret * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return ret;
}

int n, m, lim, bit, rev[maxn<<1];
ll ginv, inv2, F[maxn<<1], G[maxn<<1], c[maxn<<1], iv[maxn<<1], f[maxn<<1];

void init()
{
    ginv = qpow(g, mod - 2);
    inv2 = (mod + 1) >> 1;
}

void NTT_init(int x)
{
    lim = 1;
    bit = 0;
    while(lim <= x)
    {
        lim <<= 1;
        ++ bit;
    }
    for(int i = 1; i < lim; ++i)
        rev[i] = (rev[i>>1] >> 1) | ((i & 1) << (bit - 1));
}

void NTT(ll *x, int y)
{
    for(int i = 1; i < lim; ++i)
        if(i < rev[i])
            swap(x[i], x[rev[i]]);
    ll wn, w, u, v;
    for(int i = 1; i < lim; i <<= 1)
    {
        wn = qpow((y == 1)? g: ginv, (mod - 1) / (i << 1));
        for(int j = 0; j < lim; j += (i << 1))
        {
            w = 1;
            for(int k = 0; k < i; ++k)
            {
                u = x[j+k];
                v = x[j+k+i] * w % mod;
                x[j+k] = add(u, v);
                x[j+k+i] = rdc(u, v);
                w = w * wn % mod;
            }
        }
    }
    if(y == -1)
    {
        ll linv = qpow(lim, mod - 2);
        for(int i = 0; i < lim; ++i)
            x[i] = x[i] * linv % mod;
    }
}

void get_inv(ll *x, ll *y, int len)
{
    if(len == 1)
    {
        x[0] = qpow(y[0], mod - 2);
        return ;
    }
    get_inv(x, y, (len + 1) >> 1);
    for(int i = 0; i < len; ++i)
        c[i] = y[i];
    NTT_init(len << 1);
    NTT(x, 1);
    NTT(c, 1);
    for(int i = 0; i < lim; ++i)
    {
        x[i] = rdc(add(x[i], x[i]), (c[i] * x[i] % mod) * x[i] % mod);
        c[i] = 0;
    }
    NTT(x, -1);
    for(int i = len; i < lim; ++i)
        x[i] = 0;
}

void get_sqr(ll *x, ll *y, int len)
{
    if(len == 1)
    {
        x[0] = 1;
        return ;
    }
    get_sqr(x, y, (len + 1) >> 1);
    get_inv(iv, x, len);
    for(int i = 0; i < len; ++i)
        c[i] = y[i];
    NTT_init(len << 1);
    NTT(c, 1);
    NTT(iv, 1);
    for(int i = 0; i < lim; ++i)
    {
        c[i] = c[i] * iv[i] % mod;
        iv[i] = 0;
    }
    NTT(c, -1);
    for(int i = 0; i < len; ++i)
        x[i] = add(c[i], x[i]) * inv2 % mod;
    for(int i = 0; i < lim; ++i)
        c[i] = 0;
}

int main()
{
    n = read(); m = read();
    init();
    int x;
    for(int i = 1; i <= n; ++i)
    {
        x = read();
        G[x] = 1;
    }
    for(int i = 0; i <= 100000; ++i)
        G[i] = rdc(0, 4 * G[i] % mod);
    G[0] = 1;
    get_sqr(F, G, 100001);
    F[0] = add(F[0], 1);
    get_inv(f, F, 100001);
    for(int i = 1; i <= m; ++i)
        printf("%d
", add(f[i], f[i]));
    return 0;
}
View Code

以上是关于CF438E The Child and Binary Tree——生成函数的主要内容,如果未能解决你的问题,请参考以下文章

CF438E The Child and Binary Tree

bzoj 3625(CF 438E)The Child and Binary Tree——多项式开方

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

CF438D The Child and Sequence

CF(438D) The Child and Sequence(线段树)

CF438D The Child and Sequence 线段树