传送门


设生成函数\(C(x) = \sum\limits_{i=0}^\infty [\exists c_j = i]x^i\),答案数组为\(f_1 , f_2 , ..., f_m\),\(F(x) = \sum\limits_{i=1}^m f_ix^i + 1\)

注意到选出一棵合法的二叉树,只需要选择一个合法的权值作为根的权值,选择一棵合法的二叉树(可以为空)作为根的左儿子,选择一棵合法的二叉树(可以为空)作为根的右儿子即可。那么有\(F(x) - 1 = F(x) * F(x) * C(x)\),左边\(-1\)的原因是选出来的二叉树不可能权值和为\(0\)。

化简得到\(C(x)F^2(x) - F(x) + 1 = 0\),由初中知识得到\(F(x) = \frac{1 \pm \sqrt{1 - 4C(x)}}{2C(x)} = \frac{2}{1 \mp \sqrt{1 - 4C(x)}}\)

注意\([x^0]C(x) = 0\),所以\(C(x)\)不存在逆,所以必须上下同乘\(1 \mp \sqrt{1 - 4C(x)}\)把\(C(x)\)约掉。

但是现在仍然有\(2\)个答案。注意到,\([x^0](1 - \sqrt{1 - 4C(x)})=0\)不存在逆,而\(1 + \sqrt{1 - 4C(x)}\)存在逆,所以\(F(x) = \frac{2}{1 + \sqrt{1 - 4C(x)}}\)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<vector>
#include<cmath>
#include<random>
#include<cassert>
//This code is written by Itst
using namespace std;

const int mod = 998244353;
inline int read(bool flg = 0){
    int a = 0;
    char c = getchar();
    bool f = 0;
    while(!isdigit(c) && c != EOF){
        if(c == '-')
            f = 1;
        c = getchar();
    }
    if(c == EOF)
        exit(0);
    while(isdigit(c)){
        if(flg)
            a = (a * 10ll + c - 48) % mod;
        else
            a = a * 10 + c - 48;
        c = getchar();
    }
    if(flg) a += mod;
    return f ? -a : a;
}

const int MAXN = (1 << 19) + 7 , MOD = 998244353;
#define PII pair < int , int >
#define st first
#define nd second

PII mul(PII a , PII b , int val){
    return PII((1ll * a.st * b.st + 1ll * a.nd * b.nd % MOD * val) % MOD , (1ll * a.st * b.nd + 1ll * a.nd * b.st) % MOD);
}

int poww(PII a , int b , int val){
    PII cur = PII(1 , 0);
    while(b){
        if(b & 1) cur = mul(cur , a , val);
        a = mul(a , a , val);
        b >>= 1;
    }
    return cur.st;
}

inline int poww(long long a , int b){
    int times = 1;
    while(b){
        if(b & 1)
            times = times * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return times;
}

int calc_Surplus(int x){
    mt19937 rnd(time(0));
    int a = rnd() % MOD;
    while(poww((1ll * a * a - x + MOD) % MOD , (MOD - 1) / 2) != MOD - 1)
        a = rnd() % MOD;
    return poww(PII(a , 1) , (MOD + 1) / 2 , (1ll * a * a - x + MOD) % MOD);
}

namespace poly{
    const int G = 3 , INV = (MOD + 1) / G;
    int A[MAXN] , B[MAXN] , C[MAXN] , D[MAXN] , E[MAXN];
    int a[MAXN] , b[MAXN] , c[MAXN] , d[MAXN];
    int need , inv , dir[MAXN] , _inv[MAXN];
#define clear(x) memset(x , 0 , sizeof(int) * need)

    void init(int len){
        need = 1;
        while(need < len)
            need <<= 1;
        inv = poww(need , MOD - 2);
        for(int i = 1 ; i < need ; ++i)
            dir[i] = (dir[i >> 1] >> 1) | (i & 1 ? need >> 1 : 0);
    }

    void init_inv(){
        _inv[1] = 1;
        for(int i = 2 ; i < MAXN ; ++i)
            _inv[i] = MOD - 1ll * (MOD / i) * _inv[MOD % i] % MOD;
    }

    void NTT(int *arr , int type){
        for(int i = 1 ; i < need ; ++i)
            if(i < dir[i])
                arr[i] ^= arr[dir[i]] ^= arr[i] ^= arr[dir[i]];
        for(int i = 1 ; i < need ; i <<= 1){
            int wn = poww(type == 1 ? G : INV , (MOD - 1) / i / 2);
            for(int j = 0 ; j < need ; j += i << 1){
                long long w = 1;
                for(int k = 0 ; k < i ; ++k , w = w * wn % MOD){
                    int x = arr[j + k] , y = arr[i + j + k] * w % MOD;
                    arr[j + k] = x + y >= MOD ? x + y - MOD : x + y;
                    arr[i + j + k] = x < y ? x + MOD - y : x - y;
                }
            }
        }
    }

    void mul(int *a , int *b){
        NTT(a , 1);NTT(b , 1);
        for(int i = 0 ; i < need ; ++i)
            a[i] = 1ll * a[i] * b[i] % MOD;
        NTT(a , -1);
    }

    void getInv(int *a , int *b , int len){
        if(len == 1){
            b[0] = poww(a[0] , MOD - 2);
            return;
        }
        getInv(a , b , (len + 1) >> 1);
        memcpy(A , a , sizeof(int) * len);
        memcpy(B , b , sizeof(int) * len);
        init(len * 3);
        NTT(A , 1);NTT(B , 1);
        for(int i = 0 ; i < need ; ++i)
            A[i] = 1ll * A[i] * B[i] % MOD * B[i] % MOD;
        NTT(A , -1);
        for(int i = 0 ; i < len ; ++i)
            b[i] = (2 * b[i] - 1ll * A[i] * inv % MOD + MOD) % MOD;
        clear(A);clear(B);
    }

    void getSqrt(int *a , int *b , int len){
        if(len == 1){
            b[0] = calc_Surplus(a[0]);
            if(MOD - b[0] < b[0]) b[0] = MOD - b[0];
            return;
        }
        getSqrt(a , b , (len + 1) >> 1);
        getInv(b , C , len);
        memcpy(A , a , sizeof(int) * len);
        init(len * 2);
        mul(A , C);
        for(int i = 0 ; i < len ; ++i)
            b[i] = _inv[2] * (b[i] + 1ll * A[i] * inv % MOD) % MOD;
        clear(A);clear(C);
    }
}
using namespace poly;
int F[MAXN] , N , M;

int main(){
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    //freopen("out","w",stdout);
#endif
    init_inv();
    N = read() , M = read();
    for(int i = 1 ; i <= N ; ++i)
        F[read()] = MOD - 4;
    F[0] = 1;
    getSqrt(F , a , M + 1);
    ++a[0];
    getInv(a , b , M + 1);
    for(int i = 1 ; i <= M ; ++i)
        printf("%d\n" , b[i] * 2 % MOD);
    return 0;
}

CF438E The Child and Binary Tree 生成函数、多项式开根的更多相关文章

  1. cf438E. The Child and Binary Tree(生成函数 多项式开根 多项式求逆)

    题意 链接 Sol 生成函数博大精深Orz 我们设\(f(i)\)表示权值为\(i\)的二叉树数量,转移的时候可以枚举一下根节点 \(f(n) = \sum_{w \in C_1 \dots C_n} ...

  2. 【BZOJ3625】【CF438E】小朋友和二叉树 NTT 生成函数 多项式开根 多项式求逆

    题目大意 考虑一个含有\(n\)个互异正整数的序列\(c_1,c_2,\ldots ,c_n\).如果一棵带点权的有根二叉树满足其所有顶点的权值都在集合\(\{c_1,c_2,\ldots ,c_n\ ...

  3. Codeforces 438E The Child and Binary Tree - 生成函数 - 多项式

    题目传送门 传送点I 传送点II 传送点III 题目大意 每个点的权值$c\in {c_{1}, c_{2}, \cdots, c_{n}}$,问对于每个$1\leqslant s\leqslant ...

  4. 【CF438E】The Child and Binary Tree(多项式运算,生成函数)

    [CF438E]The Child and Binary Tree(多项式运算,生成函数) 题面 有一个大小为\(n\)的集合\(S\) 问所有点权都在集合中,并且点权之和分别为\([0,m]\)的二 ...

  5. [题解] CF438E The Child and Binary Tree

    CF438E The Child and Binary Tree Description 给一个大小为\(n\)的序列\(C\),保证\(C\)中每个元素各不相同,现在你要统计点权全在\(C\)中,且 ...

  6. [BZOJ 3625] [Codeforces 438E] 小朋友的二叉树 (DP+生成函数+多项式开根+多项式求逆)

    [BZOJ 3625] [Codeforces 438E] 小朋友的二叉树 (DP+生成函数+多项式开根+多项式求逆) 题面 一棵二叉树的所有点的点权都是给定的集合中的一个数. 让你求出1到m中所有权 ...

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

    传送门 可以……这很多项式开根模板……而且也完全不知道大佬们怎么把这题的式子推出来的…… 首先,这题需要多项式开根和多项式求逆.多项式求逆看这里->这里,这里讲一讲多项式开根 多项式开方:已知多 ...

  8. BZOJ3625 [Codeforces Round #250]小朋友和二叉树(生成函数+多项式开根)

    设f(n)为权值为n的神犇二叉树个数.考虑如何递推求这个东西. 套路地枚举根节点的左右子树.则f(n)=Σf(i)f(n-i-cj),cj即根的权值.卷积的形式,cj也可以通过卷上一个多项式枚举.可以 ...

  9. CF438E The Child and Binary Tree(生成函数,NTT)

    题目链接:洛谷 CF原网 题目大意:有 $n$ 个互不相同的正整数 $c_i$.问对于每一个 $1\le i\le m$,有多少个不同形态(考虑结构和点权)的二叉树满足每个点权都在 $c$ 中出现过, ...

随机推荐

  1. [六] 函数式接口的复合方法示例 predicate 谓词逻辑运算 Function接口 组合运算 比较器 逆序 比较链

    复合的方法 有些函数式接口提供了允许复合的方法 也就是可以将Lambda表达式复合成为一个更加复杂的方法 之前的章节中有说到: 接口中的compose, andThen, and, or, negat ...

  2. Spring Boot 2.x(九):遇到跨域不再慌

    什么是跨域 首先,我们需要了解一下一个URL是怎么组成的: // 协议 + 域名(子域名 + 主域名) + 端口号 + 资源地址 http: + // + www.baidu.com + :8080/ ...

  3. Java——多态浅析

    前言 在面向对象程序设计语言中,多态是继数据抽象和继承之后的第三种基本特性.多态的含义是什么,有什么作用以及在Java中是怎么实现的?下面将做介绍. 什么是多态 简单点说就是"一个接口,多种 ...

  4. YYModel底层解析- Runtime

    这段时间一直在忙新的需求,没有时间来整理代码,发表自己技术博客,今天我们来看一下YYModel的底层解析以及如何使用,希望对大家有所帮助! 一 概述 概括 YYModel是一个轻量级的JSON模型转换 ...

  5. 【转载】网站服务器运维记实:阿里云1核2G突发性能t5服务器突然变得卡顿

    阿里云突发性能服务器1核2G的t5服务器在高资源利用率的情况下运行一段时间后,发现服务器反应变得很慢,通过windows远程桌面连接上服务器后查看到CPU性能一直在90%到100%之间,无法降下来.前 ...

  6. Powerdesigner逆向工程64位Oracle数据库

    Powerdesigner老版本不支持64位Client,新版本弄不到破解码 解决方法,用Powerdesigner+32位Oracle Clent访问64位Oracle Server 遇到的坑分享下 ...

  7. Scrapy-Redis分布式爬虫常规操作

    一.X-path 的常规用法1./是从根节点选取,有顺序2.//从当前节点选择文档中的节点,无顺序3..选取当前节点4...选取当前节点的父节点5.@选取属性6. //div[@class='docl ...

  8. [日常] Go-逐行读取文本信息

    go逐行读取文本信息:1.os包提供了操作系统函数的不依赖平台的接口,Open方法打开一个文件用于读取,func Open(name string) (file *File, err error)2. ...

  9. ionic3 导航的应用(页面跳转与参数传递)

    about.html(跳转页面) <ion-content padding> <ion-list> <ion-item *ngFor="let he of co ...

  10. Java基础static的探究

    static方法就是没有this的方法. 在static方法内部不能调用非静态方法, 但是在非静态的方法中可以调用静态的方法和变量. 而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用stati ...