[BZOJ 3625] [Codeforces 438E] 小朋友的二叉树 (DP+生成函数+多项式开根+多项式求逆)
[BZOJ 3625] [Codeforces 438E] 小朋友的二叉树 (DP+生成函数+多项式开根+多项式求逆)
题面
一棵二叉树的所有点的点权都是给定的集合中的一个数。
让你求出1到m中所有权值为i的二叉树的个数。
两棵树不同当且仅当树的形态不一样或者是树的某个点的点权不一样
分析
设\(c(i)\)表示数值i是否在集合中。\(f(i)\)表示权值为i的二叉树的个数。那么
\]
其中\(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\)
解函数方程,得:
\]
如果符号取-,那么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+生成函数+多项式开根+多项式求逆)的更多相关文章
- BZOJ #3625 CF #438E 小朋友和二叉树
清真多项式题 BZOJ #3625 codeforces #438E 题意 每个点的权值可以在集合$ S$中任取 求点权和恰好为$[1..n]$的不同的二叉树数量 数据范围全是$ 10^5$ $ So ...
- [BZOJ3625][CF438E]小朋友和二叉树 (多项式开根,求逆)
题面 题解 设多项式的第a项为权值和为a的二叉树个数,多项式的第a项表示是否为真,即 则,所以F是三个多项式的卷积,其中包括自己: ,1是F的常数项,即. 我们发现这是一个一元二次方程,可以求出,因为 ...
- 【BZOJ3625】【CF438E】小朋友和二叉树 NTT 生成函数 多项式开根 多项式求逆
题目大意 考虑一个含有\(n\)个互异正整数的序列\(c_1,c_2,\ldots ,c_n\).如果一棵带点权的有根二叉树满足其所有顶点的权值都在集合\(\{c_1,c_2,\ldots ,c_n\ ...
- BZOJ 3625:小朋友和二叉树 多项式开根+多项式求逆+生成函数
生成函数这个东西太好用了~ code: #include <bits/stdc++.h> #define ll long long #define setIO(s) freopen(s&q ...
- 【BZOJ3625】【codeforces438E】小朋友和二叉树 生成函数+多项式求逆+多项式开根
首先,我们构造一个函数$G(x)$,若存在$k∈C$,则$[x^k]G(x)=1$. 不妨设$F(x)$为最终答案的生成函数,则$[x^n]F(x)$即为权值为$n$的神犇二叉树个数. 不难推导出,$ ...
- Codeforces 250 E. The Child and Binary Tree [多项式开根 生成函数]
CF Round250 E. The Child and Binary Tree 题意:n种权值集合C, 求点权值和为1...m的二叉树的个数, 形态不同的二叉树不同. 也就是说:不带标号,孩子有序 ...
- BZOJ3625 [Codeforces Round #250]小朋友和二叉树(生成函数+多项式开根)
设f(n)为权值为n的神犇二叉树个数.考虑如何递推求这个东西. 套路地枚举根节点的左右子树.则f(n)=Σf(i)f(n-i-cj),cj即根的权值.卷积的形式,cj也可以通过卷上一个多项式枚举.可以 ...
- [BZOJ3625][Codeforces Round #250]小朋友和二叉树 多项式开根+求逆
https://www.lydsy.com/JudgeOnline/problem.php?id=3625 愉快地列式子.设\(F[i]\)表示权值为\(i\) 的子树的方案数,\(A[i]\)为\( ...
- 【XSY2730】Ball 多项式exp 多项式ln 多项式开根 常系数线性递推 DP
题目大意 一行有\(n\)个球,现在将这些球分成\(k\) 组,每组可以有一个球或相邻两个球.一个球只能在至多一个组中(可以不在任何组中).求对于\(1\leq k\leq m\)的所有\(k\)分别 ...
随机推荐
- 【NOIP2016提高A组模拟9.14】数列编辑器
题目 分析 比赛上,没有注意到询问只询问光标前面,于是只打了个暴力. 因为询问只询问光标前面,首先,当光标向后每移动到一个位置,顺便将这个位置的前缀和,和最大前缀和求出来. 总之,模拟 #includ ...
- springCloud——Eureka、Ribbon理解
一. 服务注册中心.服务提供者.服务消费者 如何通信? 客户端: 应用主类中配置@EnableDiscoveryClient application.properties中配置defaultZone指 ...
- 谁掳走了 nginx.pid 文件?
1.重载配置 执行 nginx -s reload 命令,报错:找不到 nginx.pid 文件,无法打开.曾经屡试不爽的命令,此时,竟然失灵了? 刚开始,我一头雾水,有点丈二和尚摸不着头脑… ...
- php上传大文件
1.使用PHP的创始人 Rasmus Lerdorf 写的APC扩展模块来实现(http://pecl.php.net/package/apc) APC实现方法: 安装APC,参照官方文档安装,可以使 ...
- latex beamer技巧
%章节标题\section{Related work(LSH)} %开始一页ppt \begin{frame}{Related work}{} \partitle{Locality-Sensitive ...
- chrome插件报错原因
Chrome报错提示Unchecked runtime.lastError: The message port closed before a response was received. 出错原因: ...
- Oracle-手工生成AWR
运行awrrpt脚本 SQL> @?/rdbms/admin/awrrpt Current Instance ~~~~~~~~~~~~~~~~ DB Id DB Name ...
- 一款基于jQuery Ajax的等待效果
特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...
- insert和insertSelective区别
两者的区别在于如果选择insert 那么所有的字段都会添加一遍即使没有值 <insert id="insert" parameterType="com.ego.po ...
- NDK下编译JNI
NDK环境下编译JNI 下载demo.tar.gz然后解压 弄个套路 1.编辑build.sh设置好NDK目录 2.把cpp文件放到code下面 运行sh build.sh即可