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

题面

一棵二叉树的所有点的点权都是给定的集合中的一个数。

让你求出1到m中所有权值为i的二叉树的个数。

两棵树不同当且仅当树的形态不一样或者是树的某个点的点权不一样

分析

设\(c(i)\)表示数值i是否在集合中。\(f(i)\)表示权值为i的二叉树的个数。那么

\[f(n)=\sum_{i=1}^n c(i) \sum_{j=0}^{n-i} f(j)f(n-i-j)
\]

其中\(i\)表示根节点的权值,那么左右子树的权值和为\(n-i\),枚举左右子树分别的权值\(j,n-i-j\),为\(\sum_{j=0}^{n-i} f(j)f(n-i-j)\)

我们把式子化成卷积的形式,设\(F,C\)为\(f,c\)的生成函数

\(F(x)=F(x)^2C(x)+1\)

解函数方程,得:

\[F(x)=\frac{1 \pm {\sqrt {1-4C(x)}} }{ 2C(x)}=\frac{2}{1 \mp \sqrt{1-4C(x)}}
\]

如果符号取-,那么x=0时分母为0无意义。

因此\(F(x)=\frac{2}{1+\sqrt{1-4C(x)}}\)

多项式开方和多项式求逆即可。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxn 400000
#define G 3
#define invG 332748118
#define inv2 499122177
#define mod 998244353
using namespace std;
typedef long long ll;
inline ll fast_pow(ll x,ll k){
ll ans=1;
while(k){
if(k&1) ans=ans*x%mod;
x=x*x%mod;
k>>=1;
}
return ans;
}
inline ll inv(ll x){
return fast_pow(x,mod-2);
} void NTT(ll *x,int n,int type){
static int rev[maxn+5];
int tn=1,k=0;
while(tn<n){
tn*=2;
k++;
}
for(int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
for(int i=0;i<n;i++) if(i<rev[i]) swap(x[i],x[rev[i]]);
for(int len=1;len<n;len*=2){
int sz=len*2;
ll gn1=fast_pow((type==1?G:invG),(mod-1)/sz);
for(int l=0;l<n;l+=sz){
int r=l+len-1;
ll gnk=1;
for(int i=l;i<=r;i++){
ll tmp=x[i+len];
x[i+len]=(x[i]-gnk*tmp%mod+mod)%mod;
x[i]=(x[i]+gnk*tmp%mod)%mod;
gnk=gnk*gn1%mod;
}
}
}
if(type==-1){
ll invn=inv(n);
for(int i=0;i<n;i++) x[i]=x[i]*invn%mod;
}
}
void mul(ll *a,ll *b,ll *ans,int n){
NTT(a,n,1);
NTT(b,n,1);
for(int i=0;i<n;i++) ans[i]=a[i]*b[i]%mod;
NTT(ans,n,-1);
} void get_inv(ll *a,ll *b,int n){
static ll tmpa[maxn+5],tmpb[maxn+5];
b[0]=inv(a[0]);
int len;
for(len=1;len<n*2;len*=2){
int sz=len*2;
for(int i=0;i<len;i++){
tmpa[i]=a[i];
tmpb[i]=b[i];
}
NTT(tmpa,sz,1);
NTT(tmpb,sz,1);
for(int i=0;i<sz;i++) b[i]=tmpb[i]*(2-tmpb[i]*tmpa[i]%mod+mod)%mod;
NTT(b,sz,-1);
for(int i=len;i<sz;i++) b[i]=0;
}
for(int i=0;i<len;i++) tmpa[i]=tmpb[i]=0;
for(int i=n;i<len;i++) b[i]=0;
} void get_sqrt(ll *a,ll *b,int n){
static ll tmpa[maxn+5],invb[maxn+5];
b[0]=1;
int len;
for(len=1;len<n*2;len*=2){
int sz=len*2;
for(int i=0;i<len;i++) tmpa[i]=a[i];
get_inv(b,invb,len);
mul(tmpa,invb,tmpa,sz);
for(int i=0;i<len;i++) b[i]=inv2*(tmpa[i]+b[i])%mod;
for(int i=len;i<sz;i++) b[i]=0;
}
for(int i=0;i<len;i++) tmpa[i]=invb[i]=0;
for(int i=n;i<len;i++) b[i]=0;
} int n,m;
ll c[maxn+5],sqtc[maxn+5],isqtc[maxn+5];
int main(){
int x;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&x);
c[x]++;
}
int dn=1;
while(dn<=m) dn*=2;
for(int i=1;i<dn;i++) c[i]=((-4)*c[i]+mod)%mod;
c[0]++;//sqrt(1-4C)
get_sqrt(c,sqtc,dn);
sqtc[0]++;//1+sqrt(1-4C)
get_inv(sqtc,isqtc,dn);
for(int i=0;i<=m;i++) isqtc[i]=isqtc[i]*2%mod;//2/(1+sqrt(1-4C)
for(int i=1;i<=m;i++) printf("%lld\n",isqtc[i]);
}

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

  1. BZOJ #3625 CF #438E 小朋友和二叉树

    清真多项式题 BZOJ #3625 codeforces #438E 题意 每个点的权值可以在集合$ S$中任取 求点权和恰好为$[1..n]$的不同的二叉树数量 数据范围全是$ 10^5$ $ So ...

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

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

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

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

  4. BZOJ 3625:小朋友和二叉树 多项式开根+多项式求逆+生成函数

    生成函数这个东西太好用了~ code: #include <bits/stdc++.h> #define ll long long #define setIO(s) freopen(s&q ...

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

    首先,我们构造一个函数$G(x)$,若存在$k∈C$,则$[x^k]G(x)=1$. 不妨设$F(x)$为最终答案的生成函数,则$[x^n]F(x)$即为权值为$n$的神犇二叉树个数. 不难推导出,$ ...

  6. Codeforces 250 E. The Child and Binary Tree [多项式开根 生成函数]

    CF Round250 E. The Child and Binary Tree 题意:n种权值集合C, 求点权值和为1...m的二叉树的个数, 形态不同的二叉树不同. 也就是说:不带标号,孩子有序 ...

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

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

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

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

  9. 【XSY2730】Ball 多项式exp 多项式ln 多项式开根 常系数线性递推 DP

    题目大意 一行有\(n\)个球,现在将这些球分成\(k\) 组,每组可以有一个球或相邻两个球.一个球只能在至多一个组中(可以不在任何组中).求对于\(1\leq k\leq m\)的所有\(k\)分别 ...

随机推荐

  1. spark2.1.0 自定义AccumulatorV2累加少值(线程不安全)?

    一.踩坑经历 自定义的accumulator是线程不安全的,会造成累加结果不正确.自定找了很久没想到是线程不安全行成的. 二.解决方法 创建一个线程安全的集合变量(我用的是Java的Concurren ...

  2. Vue-Router的简单使用

    Vue-Router的最简单使用 1.先注册路由 2.将路由注册到VM组件中 3.定义组件 4.页面定义跳转路径 <!DOCTYPE html> <html> <head ...

  3. int 和guid做主键的时候性能的区别

    1.在经常需要做数据迁移的系统中,建议用Guid.并且在相应的外键字段,也就是用来做连接查询的字段添加非聚集索引,对于改善性能有极大的好处.where条件的字段也可以适当添加非聚集索引. 2.在使用G ...

  4. CCA(典型相关分析)

    https://www.cnblogs.com/pinard/p/6288716.html

  5. JavaScript 事件不触发

    在class上绑定的事件,点击图片的时候无法触发 <div id="files" class="files"> <div> <p& ...

  6. 自动化运维--ansible(1)

    前戏 ansible 批量在远程主机上执行命令 openpyxl 操作excel表格 puppet ansible slatstack ansible epel源 第一步: 下载epel源 wget ...

  7. 生成base64位图片验证码

    import org.springframework.util.Base64Utils; import javax.imageio.ImageIO; import java.awt.*; import ...

  8. 阶段2 JavaWeb+黑马旅游网_15-Maven基础_第3节 maven标准目录结构和常用命令_07maven常用命令

    以给的hellowordl的的代码为例. src/main/java下,这是主业务逻辑代码 里面的内容只有一个jsp的跳转 测试包下: 里面很简单的就输出了一句话 复制项目的目录 先cd进入复制的这个 ...

  9. 【奇技淫巧】过滤了字母和数字,如何写 shell

    日期:2018-08-13 11:56:26 作者:Bay0net 介绍:金融行业正式比赛的一个题目 0x01.题目信息 文中给了一个代码 <?php include 'flag.php'; i ...

  10. 中国MOOC_零基础学Java语言_第4周 循环控制_1素数和

    第4周编程题 查看帮助 返回   第4周编程题 依照学术诚信条款,我保证此作业是本人独立完成的. 温馨提示: 1.本次作业属于Online Judge题目,提交后由系统即时判分. 2.学生可以在作业截 ...