您的位置:首页 > 其它

BZOJ 3625: [Codeforces Round #250]小朋友和二叉树 dp 生成函数 多项式开根

2018-03-04 17:11 501 查看

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

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 743  Solved: 336
[Submit][Status][Discuss]

Description

我们的小朋友很喜欢计算机科学,而且尤其喜欢二叉树。
考虑一个含有n个互异正整数的序列c[1],c[2],...,c
。如果一棵带点权的有根二叉树满足其所有顶点的权值都在集合{c[1],c[2],...,c
}中,我们的小朋友就会将其称作神犇的。并且他认为,一棵带点权的树的权值,是其所有顶点权值的总和。
给出一个整数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
(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的神犇二叉树:



设 f[i] 为权值为 i 的树的个数
则枚举根的价值可得



之后 如果我们令 g(i) 表示 i 是否属于 A 我们就可以用分治fft啦!
但是BJ的目的是学习多项式开根 QwQ

令 f 的生成函数为 F j是否可行的生成函数为A
考虑过程 枚举左右子树与该根 但是不要忘记空树 所以+1



由于多项式求逆要有常数项
A没有常数项 若取减号就没常数了 所以只能取加号



之后多项式开根作为工具就可以施展拳脚了
和多项式求逆的化法一样

#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<set>
#include<map>
using namespace std;

typedef double db;

inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=300100,mod=998244353;

int inv_2;

inline int qpow(int x,int y)
{
int res(1);
while(y)
{
if(y&1) res=1ll*res*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return res;
}

int R
;

void ntt(int *x,int lim,int opt)
{
register int i,j,k,m,g,gn,tmp;
for(i=0;i<lim;++i)
{
R[i]=(i&1)*(lim>>1)+(R[i>>1]>>1);
if(R[i]<i) swap(x[i],x[R[i]]);
}
for(m=2;m<=lim;m<<=1)
{
k=m>>1;
gn=qpow(3,(mod-1)/m);
for(i=0;i<lim;i+=m)
{
g=1;
for(j=0;j<k;++j,g=1ll*g*gn%mod)
{
tmp=1ll*x[i+j+k]*g%mod;
x[i+j+k]=(x[i+j]-tmp+mod)%mod;
x[i+j]=(x[i+j]+tmp)%mod;
}
}
}
if(opt==-1)
{
reverse(x+1,x+lim);
tmp=qpow(lim,mod-2);
for(i=0;i<lim;++i) x[i]=1ll*x[i]*tmp%mod;
}
}

int tmp
;

// (2-ab)*b

void get_inv(int *a,int *b,int deg)
{
if(deg==1)
{b[0]=qpow(a[0],mod-2);return ;}
get_inv(a,b,(deg>>1)+(deg&1));
int lim=1;
while(lim<(deg<<1)) lim<<=1;
memcpy(tmp,a,sizeof(int)*deg);
memset(tmp+deg,0,sizeof(int)*(lim-deg));
ntt(tmp,lim,1);ntt(b,lim,1);
for(int i=0;i<lim;++i)
b[i]=(1ll*b[i]*(2-1ll*tmp[i]*b[i]%mod)%mod+mod)%mod;
ntt(b,lim,-1);
memset(b+deg,0,sizeof(int)*(lim-deg));
}

// (b^2+a)/2b

void get_root(int *a,int *b,int *inv,int deg)
{
if(deg==1)
{b[0]=1;return ;}
get_root(a,b,inv,(deg>>1)+(deg&1));
memset(inv,0,sizeof(int)*deg);
get_inv(b,inv,deg);
int lim=1;
while(lim<(deg<<1)) lim<<=1;
memcpy(tmp,a,sizeof(int)*deg);
memset(tmp+deg,0,sizeof(int)*(lim-deg));
ntt(tmp,lim,1);ntt(b,lim,1);ntt(inv,lim,1);
for(int i=0;i<lim;++i)
b[i]=1ll*(b[i]+1ll*tmp[i]*inv[i]%mod)*inv_2%mod;
ntt(b,lim,-1);
memset(b+deg,0,sizeof(int)*(lim-deg));
}

int A
,B
,C
;

int main()
{
int n=read(),m=read();
register int i,x;
A[0]=1;
for(i=1;i<=n;++i) x=read(),A[x]=mod-4;
inv_2=qpow(2,mod-2);
x=1;while(x<=m) x<<=1;
get_root(A,B,C,x);

for(i=0;i<=m;++i) A[i]=B[i];A[0]++;
memset(B,0,sizeof(B));
get_inv(A,B,x);

for(i=1;i<=m;++i)
print((B[i]<<1)%mod),putchar('\n');
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: