BZOJ3625小朋友和二叉树【生成函数】

传送门


PROBLEM

在这里插入图片描述


SOL

在这里插入图片描述

在这里插入图片描述

F的常数项为1,G的常数项为0,带入方程,舍去减的根。(说是因为不收敛?)

多项式开根+求逆

(code附赠两种开根写法)


CODE

#include<bits/stdc++.h>
#define pf printf
#define sf scanf
#define cs const
#define ll long long
#define db double
using namespace std;
#define in red()
inline int red()
{
    int data=0;int w=1; char ch=0;
    ch=getchar();
    while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return data*w;
}
cs int N=1e5+10,mod=998244353;
inline int mul(cs int &a,cs int &b){return 1ll*a*b%mod;}
inline int add(cs int &a,cs int &b){return a+b>mod? a-mod+b:a+b;} 
inline int dec(cs int &a,cs int &b){return a-b<0? a+mod-b:a-b;}
inline int ksm(int a,int b){int ans=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ans=mul(ans,a);return ans;}
#define ri register int
typedef vector<int> node;
int lim,tim,w[30],inv[30],inv2,n,m;
node rev[30];
inline void init_w(){
	w[22]=ksm(3,(mod-1)>>23);inv[0]=1;
	for(ri i=21;~i;--i)w[i]=mul(w[i+1],w[i+1]);
	for(ri i=1,mt=ksm(2,mod-2);i<=22;++i)inv[i]=mul(inv[i-1],mt);
} 
inline void init(cs int &up){
	lim=1;tim=0;
	while(lim<up)lim<<=1,++tim;
	if(rev[tim].size())return;
	rev[tim].resize(lim);
	for(ri i=0;i<lim;++i)rev[tim][i]=(rev[tim][i>>1]>>1)|((i&1)*(lim>>1));
}
inline void ntt(node &f,bool kd){
	for(ri i=0;i<lim;++i)if(rev[tim][i]<i)swap(f[i],f[rev[tim][i]]);
	for(ri mid=1,t=0;mid<lim;mid<<=1,++t){
		for(ri i=0,d=mid<<1;i<lim;i+=d){
			for(ri j=0,now=1,p0,p1;j<mid;++j,now=mul(now,w[t])){
				p0=f[i+j],p1=mul(now,f[i+j+mid]);
				f[i+j]=add(p0,p1);f[i+j+mid]=dec(p0,p1);
			}
		}
	}
	if(kd)return;
	reverse(++f.begin(),f.end());
	for(ri i=0;i<lim;++i)f[i]=mul(f[i],inv[tim]);
}
inline node operator *(node a,node b){
	int n=a.size(),m=b.size(),tot=n+m-1;
	if(tot<=168){
		node c(tot);
		for(ri i=0;i<n;++i)
			for(ri j=0;j<m;++j)
				c[i+j]=add(c[i+j],mul(a[i],b[j]));
		return c;
	}
	init(tot);
	a.resize(lim);ntt(a,1);	
	b.resize(lim);ntt(b,1);
	for(ri i=0;i<lim;++i)a[i]=mul(a[i],b[i]);
	return ntt(a,0),a.resize(tot),a;
}
inline node node_inv(node &a,int k){
	node c,b(1,ksm(a[0],mod-2));
	for(ri lim=4,up=k<<2;lim<up;lim<<=1){
		init(lim);
		c=a;c.resize(lim>>1);
		c.resize(lim);ntt(c,1);
		b.resize(lim);ntt(b,1);
		for(ri i=0;i<lim;++i)b[i]=mul(b[i],dec(2,mul(c[i],b[i])));
		ntt(b,0);b.resize(lim>>1);
	}
	return b.resize(k),b;
}
inline node node_sqrt(node &a,int k){
	node c,b(1,1),d;
	for(ri lim=4,up=k<<2;lim<up;lim<<=1){
		d=node_inv(b,lim>>1);
		init(lim);
		c=a;c.resize(lim>>1);
		c.resize(lim);ntt(c,1);
		d.resize(lim);ntt(d,1);
		for(ri i=0;i<lim;++i)d[i]=mul(d[i],c[i]);
		ntt(d,0);b.resize(lim>>1);
		for(ri i=0,up=(lim>>1);i<up;++i)b[i]=add(b[i],d[i]),b[i]=mul(b[i],inv2);
	}
	return b.resize(k),b;
}
//inline node node_sqrt(node a,int n){
//	node b(1,1),c,d;
//	for(int lim=4;lim<(n<<2);lim<<=1){
//		c=a;c.resize(lim>>1);
//		init(lim);d=node_inv(b,lim>>1);
//		c.resize(lim);ntt(c,1);
//		d.re	size(lim);ntt(d,1);
//		for(int i=0;i<lim;i++) c[i]=mul(c[i],d[i]);
//		ntt(c,0);b.resize(lim>>1);
//		for(int i=0;i<(lim>>1);i++) b[i]=mul(inv2,add(b[i],c[i]));
//	}
//	b.resize(n);return b;
//}
node a;
signed main (){

	init_w();
	inv2=ksm(2,mod-2);
	n=in,m=in;
	a.resize(N-3);
	for(ri i=1;i<=n;++i)++a[in];
	a.resize(m+1);
	for(ri i=0;i<=m;++i)a[i]=mul(-4,a[i]);
	a[0]=add(1,a[0]);
	a=node_sqrt(a,m+1);
	a[0]=add(1,a[0]);
	a=node_inv(a,m+1);
	for(ri i=1;i<=m;++i)pf("%d\n",mul(2,a[i]));
	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值