这个题意说人话就是:一棵带标号的有根树,编号满足堆性质,根节点有$x$个儿子是叶子($x\in A$),另外的$2$个儿子也是这样的一棵树,求不同的树的个数
设$f_n$为答案,枚举那两棵子树的大小$i,j$,那么$f_i=\frac12\sum\limits_{1\leq j,k\lt i}[i-1-j-k\in A]\binom{i-1}j\binom{i-1-j}kf_jf_k$,$f_1=1$,直接做是$O(n^3)$的
把组合数拆开,记$a_i=[i\in A]\frac1{i!},f'_i=\frac{f_i}{i!},g_i=\sum\limits_{j+k=i}f'_jf'_k$,那么$f'_i=\frac1{2i}\sum\limits_{j+k=i-1}a_jg_k$,按照这个直接做,每次更新$g$,时间复杂度为$O(n^2)$
因为$f,g$的递推式都是卷积,所以考虑分治FFT,这种类CDQ分治的分治FFT主要解决形如$f_i=\sum\limits_{j+k=i}g_jh_k$的递推式,其中$g,h$中至少一个与$f$有关
如果当前分治到$[l,r]$,先递归进$[l,mid]$,然后算递推式中$j\in[l,mid],i\in[mid+1,r]$的部分,一次卷积就可以了
需要注意的是如果$g,h$都与$f$有关,那么我们还要处理$j,k\in[l,mid],i\in[mid+1,r]$的情况,但因为是分治结构,所以这种情况只会在$l=1$时出现,于是只需在$l\gt1$时再做一次即可,如果$g=h$那么直接把答案$\times2$就行了
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
int mul(int a,int b){return(ll)a*b%mod;}
int ad(int a,int b){return(a+b)%mod;}
int de(int a,int b){return(a-b)%mod;}
void inc(int&a,int b){(a+=b)%=mod;}
int pow(int a,int b){
int s=1;
while(b){
if(b&1)s=mul(s,a);
a=mul(a,a);
b>>=1;
}
return s;
}
int rev[524288],N,iN;
void pre(int n){
int i,k;
for(N=1,k=0;N<n;N<<=1)k++;
for(i=0;i<N;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
iN=pow(N,mod-2);
}
void ntt(int*a,int on){
int i,j,k,t,w,wn;
for(i=0;i<N;i++){
if(i<rev[i])swap(a[i],a[rev[i]]);
}
for(i=2;i<=N;i<<=1){
wn=pow(3,on==1?(mod-1)/i:mod-1-(mod-1)/i);
for(j=0;j<N;j+=i){
w=1;
for(k=0;k<i>>1;k++){
t=mul(a[i/2+j+k],w);
a[i/2+j+k]=de(a[j+k],t);
a[j+k]=ad(a[j+k],t);
w=mul(w,wn);
}
}
}
if(on==-1){
for(i=0;i<N;i++)a[i]=mul(a[i],iN);
}
}
int ta[524288],tb[524288];
void conv(){
ntt(ta,1);
ntt(tb,1);
for(int i=0;i<N;i++)ta[i]=mul(ta[i],tb[i]);
ntt(ta,-1);
}
int fac[200010],rfac[200010];
char s[200010];
int a[200010],f[200010],g[200010],inv[400010];
void solve(int l,int r){
if(l==r)return;
int mid=(l+r)>>1,i;
solve(l,mid);
//f*f->g
pre(r-l+mid-l+1);
memset(ta,0,N<<2);
memset(tb,0,N<<2);
for(i=1;i<=r-l;i++)ta[i-1]=f[i];
for(i=l;i<=mid;i++)tb[i-l]=f[i];
conv();
if(l>1){
for(i=mid-l;i<r-l;i++)ta[i]=mul(ta[i],2);
}
for(i=1;i<=r-mid;i++)inc(g[i+mid],ta[i+mid-l-1]);
//a*g->f
memset(ta,0,N<<2);
memset(tb,0,N<<2);
for(i=0;i<r-l;i++)ta[i]=a[i];
for(i=l;i<=mid;i++)tb[i-l]=g[i];
conv();
for(i=1;i<=r-mid;i++)inc(f[i+mid],mul(inv[2*(i+mid)],ta[i+mid-l-1]));
solve(mid+1,r);
}
int main(){
int n,i;
scanf("%d%s",&n,s);
fac[0]=1;
for(i=1;i<=n;i++)fac[i]=mul(fac[i-1],i);
rfac[n]=pow(fac[n],mod-2);
for(i=n;i>0;i--)rfac[i-1]=mul(rfac[i],i);
inv[1]=1;
for(i=2;i<=2*n;i++)inv[i]=-mul(mod/i,inv[mod%i]);
for(i=0;i<n;i++)a[i]=s[i]=='1'?rfac[i]:0;
f[1]=1;
solve(1,n);
for(i=1;i<=n;i++)printf("%d\n",ad(mul(f[i],fac[i]),mod));
}