3625: [Codeforces Round #250]小朋友和二叉树

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 304  Solved: 130
[Submit][Status][Discuss]

Description

我们的小朋友很喜欢计算机科学,而且尤其喜欢二叉树。
考虑一个含有n个互异正整数的序列c[1],c[2],...,c[n]。如果一棵带点权的有根二叉树满足其所有顶点的权值都在集合{c[1],c[2],...,c[n]}中,我们的小朋友就会将其称作神犇的。并且他认为,一棵带点权的树的权值,是其所有顶点权值的总和。
给出一个整数m,你能对于任意的s(1<=s<=m)计算出权值为s的神犇二叉树的个数吗?请参照样例以更好的理解什么样的两棵二叉树会被视为不同的。
我们只需要知道答案关于998244353(7*17*2^23+1,一个质数)取模后的值。

Input

第一行有2个整数 n,m(1<=n<=10^5; 1<=m<=10^5)。
第二行有n个用空格隔开的互异的整数 c[1],c[2],...,c[n](1<=c[i]<=10^5)。

Output

输出m行,每行有一个整数。第i行应当含有权值恰为i的神犇二叉树的总数。请输出答案关于998244353(=7*17*2^23+1,一个质数)取模后的结果。

Sample Input

样例一:
2 3
1 2
样例二:
3 10
9 4 3
样例三:
5 10
13 10 6 4 15

Sample Output

样例一:
1
3
9
样例二:
0
0
1
1
0
2
4
2
6
15
样例三:
0
0
0
1
0
1
0
2
0
5

HINT

对于第一个样例,有9个权值恰好为3的神犇二叉树:

Source

[Submit][Status][Discuss]

据说是道生成函数+多项式计算水题,所以机房里只有我这样的蒟蒻才不会做。

设F(x)中的i次方项系数表示权值和为i的二叉树的个数。(这个就是最终答案函数)

设C(x)中的i次方项系数表示权值i是否出现在可选集合内。(这其实就是C集合的bitset表示)

然后得到$F=CF^2+1$,其中C为枚举根节点权值,两个F分别是左右子树,+1代表可能是一棵空树。

化简得到$CF^2-F+1=0$,根据一元二次方程求根公式,这个多项式方程的根就是$\frac{1\pm\sqrt{1-4C}}{2C}$。

然后嘞,就支持一下多项式开方,多项式求逆好了,其中需要用到NTT和两个倍增算法,然而蒟蒻的我并不会,只好向Monster_Yi大佬和LincHpin大爷虚心请教。

 #include <cstdio>
#include <cstring> template <class T>
inline void read(T &x)
{
x = ;
char c = getchar();
while (c < )c = getchar();
while (c > )x = x* + c - , c = getchar();
} template <class T>
inline void swap(T &a, T &b)
{
T c;
c = a;
a = b;
b = c;
} const int P = ;
const int D = ;
const int N = ; inline int pow(int a, int b)
{
int r = ; while (b)
{
if (b & )
r = 1LL * r * a % P; b >>= , a = 1LL * a * a % P;
} return r;
} inline void ntt(int *a, int len, int type)
{
for (int i = , t = ; i < len; ++i)
{
if (i > t)swap(a[i], a[t]);
for (int j = (len >> ); (t ^= j) < j; j >>= );
} for (int h = ; h <= len; h <<= )
{
int wn = pow(, (P - ) / h); for (int i = ; i < len; i += h)
{
int wk = ; for (int j = ; j < (h >> ); ++j, wk = 1LL * wk * wn % P)
{
int t = 1LL * wk * a[i + j + (h >> )] % P; a[i + j + (h >> )] = (a[i + j] - t + P) % P;
a[i + j] = (a[i + j] + t) % P;
}
}
} if (type == -)
{
for (int i = ; i < (len >> ); ++i)
swap(a[i], a[len - i]); int inv = pow(len, P - ); for (int i = ; i < len; ++i)
a[i] = 1LL * a[i] * inv % P;
}
} void inv(int *a, int *b, int len)
{
if (len == )
b[] = pow(a[], P - );
else
{
static int t[N]; inv(a, b, len >> ); memcpy(t, a, len * sizeof(int));
memset(t + len, , len * sizeof(int)); ntt(t, len << , );
ntt(b, len << , ); for (int i = ; i < len << ; ++i)
b[i] = 1LL * b[i] * ( - 1LL * t[i] * b[i] % P + P) % P; ntt(b, len << , -); memset(b + len, , len * sizeof(int));
}
} void sqrt(int *a, int *b, int len)
{
if (len == )
b[] = ;
else
{
static int c[N], d[N]; sqrt(a, b, len >> ); memset(d, , len * sizeof(int));
memset(d + len, , len * sizeof(int)); inv(b, d, len); memcpy(c, a, len * sizeof(int));
memset(c + len, , len * sizeof(int)); ntt(c, len << , );
ntt(b, len << , );
ntt(d, len << , ); for (int i = ; i < len << ; ++i)
b[i] = (1LL * c[i] * d[i] % P + b[i]) % P * D % P; ntt(b, len << , -); memset(b + len, , len * sizeof(int));
}
} int n, m, len; int a[N], b[N]; signed main(void)
{
read(n);
read(m); a[] = ; for (len = ; len <= m; len <<= ); for (int i = , x; i <= n; ++i)
if (read(x), x <= m)a[x] = P - ; sqrt(a, b, len); memcpy(a, b, len * sizeof(int)), ++a[];
memset(b, , len * sizeof(int)), inv(a, b, len);
memcpy(a, b, len * sizeof(int)); for (int i = ; i <= m; ++i)
printf("%d\n", (a[i] << ) % P);
}

@Author: YouSiki

BZOJ 3625: [Codeforces Round #250]小朋友和二叉树的更多相关文章

  1. BZOJ 3625 [Codeforces Round #250]小朋友和二叉树 ——NTT 多项式求逆 多项式开根

    生成函数又有奇妙的性质. $F(x)=C(x)*F(x)*F(x)+1$ 然后大力解方程,得到一个带根号的式子. 多项式开根有解只与常数项有关. 发现两个解只有一个是成立的. 然后多项式开根.求逆. ...

  2. bzoj 3625: [Codeforces Round #250]小朋友和二叉树【NTT+多项式开根求逆】

    参考:https://www.cnblogs.com/2016gdgzoi509/p/8999460.html 列出生成函数方程,g(x)是价值x的个数 \[ f(x)=g(x)*f^2(x)+1 \ ...

  3. BZOJ3625: [Codeforces Round #250]小朋友和二叉树

    Description 我们的小朋友很喜欢计算机科学,而且尤其喜欢二叉树.考虑一个含有n个互异正整数的序列c[1],c[2],...,c[n].如果一棵带点权的有根二叉树满足其所有顶点的权值都在集合{ ...

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

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

  5. [Codeforces Round #250]小朋友和二叉树

    题目描述: bzoj luogu 题解: 生成函数ntt. 显然这种二叉树应该暴力薅掉树根然后分裂成两棵子树. 所以$f(x)= \sum_{i \in c} \sum _{j=0}^{x-c} f( ...

  6. [BZOJ3625][Codeforces Round #250]小朋友和二叉树 多项式开根+求逆

    https://www.lydsy.com/JudgeOnline/problem.php?id=3625 愉快地列式子.设\(F[i]\)表示权值为\(i\) 的子树的方案数,\(A[i]\)为\( ...

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

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

  8. Codeforces Round#250 D. The Child and Zoo(并差集)

    题目链接:http://codeforces.com/problemset/problem/437/D 思路:并差集应用,先对所有的边从大到小排序,然后枚举边的时候,如果某条边的两个顶点不在同一个集合 ...

  9. Codeforces Round #250 (Div. 2)A(英语学习)

    链接:http://codeforces.com/contest/437/problem/A A. The Child and Homework time limit per test 1 secon ...

随机推荐

  1. 搭建Hadoop的HA高可用架构(超详细步骤+已验证)

    一.集群的规划 Zookeeper集群: 192.168.182.12 (bigdata12)192.168.182.13 (bigdata13)192.168.182.14 (bigdata14) ...

  2. 实现MD5的加密和解密

    加密代码 public static string Encrypt(string Text, string sKey) { DESCryptoServiceProvider des = new DES ...

  3. POJ 1860&&3259&&1062&&2253&&1125&&2240

    六道烦人的最短路(然而都是水题) 我也不准备翻译题目了(笑) 一些是最短路的变形(比如最长路,最短路中的最长边,判环),还有一些就是裸题了. 1860:找环,只需要把SPFA的松弛条件改一下即可,这里 ...

  4. Linux 入门记录:十二、Linux 权限机制

    一.权限 权限是操作系统用来限制资源访问的机制,权限一般分为读.写.执行. 系统中每个文件都拥有特定的权限.所属用户及所属组,通过这样的机制来限制哪些用户.哪些组可以对特定的文件进行什么样的操作. 每 ...

  5. CentOS7 Rsync服务搭建-Rsync+Inotify架构实现实时同步

    一.rsync 概念 1.rsyncrsync是类unix/linux系统下的数据镜像备份工具.使用快速增量备份工具Remote Sync可以远程同步,支持本地复制,或者与其他SSH.rsync主机同 ...

  6. Unity攻击敌人时产生泛白效果

    Shader的代码如下,主要是将透明度为1的像素点输出为白色,其中_BeAttack表示角色被攻击的泛白状态 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_M ...

  7. 揭秘memset与sizeof的结合使用方法

    memset与sizeof为什么经常结合起来用呢? 一.memset介绍 memset函数是C++中的一个函数,它将从给定地址开始,逐个字节刷内存,初始化它们为给定的参数. 基本用法: void * ...

  8. UI Recorder 安装教程(一)

    前言: UI Recorder 是一款零成本UI自动化录制工具,类似于Selenium IDE. UI Recorder 要比Selenium IDE更加强大! UI Recorder 非常简单易用. ...

  9. 【助教】浅析log4j的使用

    有不少童鞋私信我一些在写代码时候遇到的问题,但是无法定位问题出在哪里,也没有日志记录,实际上,写日志是开发项目过程中很重要的一个环节,很多问题都可以从日志中找到根源,从而定位到出错位置,为解决问题提供 ...

  10. Mac 绑定Gitlab或者GitHub帐号,从新生成公钥

    1.SSH(Secure Shell)是一种安全协议,在你的电脑与GitLab服务器进行通信时,我们使用SSH密钥(SSH Keys)认证的方式来保证通信安全. 2.创建 SSH密钥,并将密钥中的公钥 ...