题意

链接

Sol

生成函数博大精深Orz

我们设\(f(i)\)表示权值为\(i\)的二叉树数量,转移的时候可以枚举一下根节点

\(f(n) = \sum_{w \in C_1 \dots C_n} \sum_{j=0}^{n-w} f(j) f(n-w-j)\)

设\(T =n-w\),后半部分变为\(\sum_{j=0}^T f(j) f(T-j)\),是个标准的卷积形式。

对于第一重循环我们可以设出现过的数的生成函数\(C(x)\)

可以得到\(f = C * f * f + 1\),+1是因为\(f[0] = 1\)

可以解得\(f = \frac{1\pm\sqrt{1-4G}}{2G} = \frac{2}{1\pm\sqrt{1-4C}}\)

现在问题来了,我们是要取\(+\)还是取\(-\)。

结论是取\(+\),因为当取\(-\)时,C中x的取值趋向于\(0\)时分母会无意义

举个例子(来自cf讨论区)

\(C = 2x - 4x^2\),\(+\sqrt{1-4C} = 1 - 4x, -\sqrt{1-4C} = -1+4x\)

后者带入得到\(F = \frac{2}{4x}\),这玩意儿显然是无解的,因为多项式有逆元的充要条件是常数项在模意义下有逆元,然而这玩意儿的常数项是0.。

感觉做这种题直接还是要先推一推暴力dp的式子吧,不然直接用生成函数推根本无从下手。。

#include<bits/stdc++.h>
#define Pair pair<int, int>
#define MP(x, y) make_pair(x, y)
#define fi first
#define se second
#define LL long long
#define ull unsigned long long
#define Fin(x) {freopen(#x".in","r",stdin);}
#define Fout(x) {freopen(#x".out","w",stdout);}
using namespace std;
const int MAXN = 1e6 + 10, INF = 1e9 + 1;
const double eps = 1e-9, pi = acos(-1);
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, M, a[MAXN], b[MAXN], c[MAXN], d[MAXN];
namespace Poly {
int rev[MAXN], GPow[MAXN], A[MAXN], B[MAXN], C[MAXN], lim, INV2;
const int G = 3, mod = 998244353;
template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
template <typename A, typename B> inline LL mul(A x, B y) {return 1ll * x * y % mod;}
template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;}
int fp(int a, int p, int P = mod) {
int base = 1;
for(; p; p >>= 1, a = 1ll * a * a % P) if(p & 1) base = 1ll * base * a % P;
return base;
}
int GetLen(int x) {
int lim = 1;
while(lim <= x) lim <<= 1;
return lim;
}
int GetOrigin(int x) {//¼ÆËãÔ­¸ù
static int q[MAXN]; int tot = 0, tp = x - 1;
for(int i = 2; i * i <= tp; i++) if(!(tp % i)) {q[++tot] = i;while(!(tp % i)) tp /= i;}
if(tp > 1) q[++tot] = tp;
for(int i = 2, j; i <= x - 1; i++) {
for(j = 1; j <= tot; j++) if(fp(i, (x - 1) / q[j], x) == 1) break;
if(j == tot + 1) return i;
}
}
void Init(/*int P,*/ int Lim) {
//mod = P; G = GetOrigin(mod); Gi = fp(G, mod - 2);
INV2 = fp(2, mod - 2);
for(int i = 1; i < Lim; i++) GPow[i] = fp(G, (mod - 1) / i);
}
void NTT(int *A, int lim, int opt) {
int len = 0; for(int N = 1; N < lim; N <<= 1) ++len;
for(int i = 1; i <= lim; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (len - 1));
for(int i = 0; i <= lim; i++) if(i < rev[i]) swap(A[i], A[rev[i]]);
for(int mid = 1; mid < lim; mid <<= 1) {
int Wn = GPow[mid << 1];
for(int i = 0; i < lim; i += (mid << 1)) {
for(int j = 0, w = 1; j < mid; j++, w = mul(w, Wn)) {
int x = A[i + j], y = mul(w, A[i + j + mid]);
A[i + j] = add(x, y), A[i + j + mid] = add(x, -y);
}
}
}
if(opt == -1) {
reverse(A + 1, A + lim);
int Inv = fp(lim, mod - 2);
for(int i = 0; i <= lim; i++) mul2(A[i], Inv);
}
}
void Mul(int *a, int *b, int N, int M) {
memset(A, 0, sizeof(A)); memset(B, 0, sizeof(B));
int lim = 1, len = 0;
while(lim <= N + M) len++, lim <<= 1;
for(int i = 0; i <= N; i++) A[i] = a[i];
for(int i = 0; i <= M; i++) B[i] = b[i];
NTT(A, lim, 1); NTT(B, lim, 1);
for(int i = 0; i <= lim; i++) B[i] = mul(B[i], A[i]);
NTT(B, lim, -1);
for(int i = 0; i <= N + M; i++) b[i] = B[i];
memset(A, 0, sizeof(A)); memset(B, 0, sizeof(B));
}
void Inv(int *a, int *b, int len) {//B1 = 2B - A1 * B^2
if(len == 1) {b[0] = fp(a[0], mod - 2); return ;}
Inv(a, b, len >> 1);
for(int i = 0; i < len; i++) A[i] = a[i], B[i] = b[i];
NTT(A, len << 1, 1); NTT(B, len << 1, 1);
for(int i = 0; i < (len << 1); i++) mul2(A[i], mul(B[i], B[i]));
NTT(A, len << 1, -1);
for(int i = 0; i < len; i++) add2(b[i], add(b[i], -A[i]));
for(int i = 0; i < (len << 1); i++) A[i] = B[i] = 0;
}
void Dao(int *a, int *b, int len) {
for(int i = 1; i < len; i++) b[i - 1] = mul(i, a[i]); b[len - 1] = 0;
}
void Ji(int *a, int *b, int len) {
for(int i = 1; i < len; i++) b[i] = mul(a[i - 1], fp(i, mod - 2)); b[0] = 0;
}
void Ln(int *a, int *b, int len) {//G(A) = \frac{A}{A'} qiudao zhihou jifen
static int A[MAXN], B[MAXN];
Dao(a, A, len);
Inv(a, B, len);
NTT(A, len << 1, 1); NTT(B, len << 1, 1);
for(int i = 0; i < (len << 1); i++) B[i] = mul(A[i], B[i]);
NTT(B, len << 1, -1);
Ji(B, b, len << 1);
memset(A, 0, sizeof(A)); memset(B, 0, sizeof(B));
}
void Exp(int *a, int *b, int len) {//F(x) = F_0 (1 - lnF_0 + A) but code ..why....
if(len == 1) return (void) (b[0] = 1);
Exp(a, b, len >> 1); Ln(b, C, len);
C[0] = add(a[0] + 1, -C[0]);
for(int i = 1; i < len; i++) C[i] = add(a[i], -C[i]);
NTT(C, len << 1, 1); NTT(b, len << 1, 1);
for(int i = 0; i < (len << 1); i++) mul2(b[i], C[i]);
NTT(b, len << 1, -1);
for(int i = len; i < (len << 1); i++) C[i] = b[i] = 0;
}
void Sqrt(int *a, int *b, int len) {
static int B[MAXN];
Ln(a, B, len);
for(int i = 0; i < len; i++) B[i] = mul(B[i], INV2);
Exp(B, b, len);
}
};
using namespace Poly; signed main() {
N = read(); M = read(); int Lim = GetLen(M); Init(4 * Lim);
for(int i = 1; i <= N; i++) a[i] = read();
for(int i = 1; i <= N; i++) b[a[i]] = (-4 + mod); add2(b[0], 1);
Sqrt(b, c, Lim);
add2(c[0], 1);
Inv(c, d, Lim);
for(int i = 1; i <= M; i++) cout << mul(2, d[i]) << '\n';
return 0;
}

cf438E. The Child and Binary Tree(生成函数 多项式开根 多项式求逆)的更多相关文章

  1. [BZOJ3625][CF438E]小朋友和二叉树 (多项式开根,求逆)

    题面 题解 设多项式的第a项为权值和为a的二叉树个数,多项式的第a项表示是否为真,即 则,所以F是三个多项式的卷积,其中包括自己: ,1是F的常数项,即. 我们发现这是一个一元二次方程,可以求出,因为 ...

  2. CF438E The Child and Binary Tree 生成函数、多项式开根

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

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

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

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

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

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

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

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

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

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

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

  8. CF438E The Child and Binary Tree

    思路 设F(x)的第x项系数为权值和为x的答案 题目中要求权值必须在集合中出现,这个不好处理,考虑再设一个C,C的第x项如果是1代表x出现在值域里,如果是0,代表x没有出现在值域里,然后由于二叉树可以 ...

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

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

随机推荐

  1. 【详记MySql问题大全集】三、安装之后没有my.ini配置文件怎么办

    系列目录 一.安装MySql 二.安装并破解Navicat 三.没有my.in配置文件怎么办 四.设置MySql的大小写敏感 五.重置MySql登陆密码 之前说过,Windows操作系统中,我们安装M ...

  2. Kubenetes---Service--实践

    1,编写创建svc的yaml文件 2,  创建service 3, 查看 4,查看svc代理那些pod , 当前没有 先创建deployment --> service 查看pod的label信 ...

  3. bootstrap treeview实现菜单树

    本博客,介绍通过Bootstrap的treeview插件实现菜单树的功能. treeview链接:http://www.htmleaf.com/Demo/201502141380.html ORM框架 ...

  4. Java 中的 String 真的是不可变吗?

    我们都知道 Java 中的 String 类的设计是不可变的,来看下 String 类的源码. public final class String implements java.io.Seriali ...

  5. 关于mysql的update、delete、和insert into能否使用别名问题

    在工作中遇到这样一个问题,就是mysql在insert into时能不能使用别名,大家会很奇怪为什么insert into使用别名呢?原因在于原来的项目中使用了user表,新项目要将user表拆分为u ...

  6. DDD实战进阶第一波(十二):开发一般业务的大健康行业直销系统(订单上下文POCO模型)

    在本系列前面的文章中,我们主要讨论了产品上下文与经销商上下文相关的实现,大家对DDD的方法与架构已经有了初步的了解. 但是在这两个界限上下文中,业务逻辑很简单,也没有用到更多的值对象的内容.从这篇文章 ...

  7. 如何在优雅地Spring 中实现消息的发送和消费

    本文将对rocktmq-spring-boot的设计实现做一个简单的介绍,读者可以通过本文了解将RocketMQ Client端集成为spring-boot-starter框架的开发细节,然后通过一个 ...

  8. 学习 spring-boot (一)

    学习文章来自:http://www.ityouknow.com/spring-boot.html Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初 ...

  9. vue中使用refs定位dom出现undefined?

    之前在公司做项目,一直感觉用ref来定位dom节点挺方便的.但是期间遇到了一个问题,就是在mounted(){}钩子里面使用this.$refs.xxx,打印出来的却是undefined? 于是我就对 ...

  10. 数据库性能测试:sysbench用法详解

    1.简介和安装 sysbench是一个很不错的数据库性能测试工具. 官方站点:https://github.com/akopytov/sysbench/ rpm包下载:https://packagec ...