bzoj 3625小朋友和二叉树 多项式求逆+多项式开根 好题

题目大意

给定n种权值
给定m
(F_i表示权值和为i的二叉树个数)
(F_1,F_2...F_m)

分析

安利博客
(F_d=F_L*F_R*C_{mid},L+mid+R=d)
(F(x)=frac {1+sqrt{1-4C(x)}}{2C(x)}=frac 2{1-sqrt{1-4C(x)}})
无解是因为(x=0)(F(x)=1)
但是(limlimits_{x ightarrow 0})(1-sqrt{1-4C(x)}趋于0)
(F)趋于INF
同理可证(F(x)=frac {1-sqrt{1-4C(x)}}{2C(x)})是正确的

姿势

求逆和开根函数中
static开一些临时数组
写起来方便
但注意初始化

solution

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int M=262145;
const LL Q=998244353;

inline int rd(){
	int x=0;bool f=1;char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
	for(;isdigit(c);c=getchar()) x=x*10+c-48;
	return f?x:-x;
}

int n,m;
LL g,ig,iv2;
LL a[M],b[M];
int rev[M];

LL pwr(LL x,LL tms){
	LL res=1;
	for(;tms>0;tms>>=1){
		if(tms&1) res=res*x%Q;
		x=x*x%Q;
	}
	return res;
}

void NTT(LL *a,int N,int fl){
	int i,j,k;
	LL W,Wn,u,v;

	for(i=0;i<N;i++) rev[i]=(rev[i>>1]>>1)|((i&1)?(N>>1):0);
	for(i=0;i<N;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);

	for(i=2;i<=N;i<<=1){
		if(fl==1) Wn=pwr(g,(Q-1)/i);
		else Wn=pwr(ig,(Q-1)/i);
		for(j=0;j<N;j+=i){
			for(W=1,k=j;k<j+i/2;k++,W=W*Wn%Q){
				u=a[k];
				v=W*a[k+i/2]%Q;
				a[k]=(u+v)%Q;
				a[k+i/2]=((u-v)%Q+Q)%Q;
			}
		}
	}
	if(fl==-1){
		LL iN=pwr(N,Q-2);
		for(i=0;i<N;i++) a[i]=a[i]*iN%Q;
	}
	
}

void INV(LL*a,LL *b,int len){
	static LL g[M],tp[M];
	if(len==1) b[0]=pwr(a[0],Q-2);
	else{
		int i;
		INV(a,b,len>>1);
		int N=len<<1;	
		for(i=0;i<(len>>1);i++) g[i]=b[i];
		for(;i<N;i++) g[i]=b[i]=0;
		for(i=0;i<len;i++) tp[i]=a[i];
		for(;i<N;i++) tp[i]=0;
		NTT(g,N,1);
		NTT(tp,N,1);
		for(i=0;i<N;i++) tp[i]=g[i]*g[i]%Q*tp[i]%Q;
		NTT(tp,N,-1);
		for(i=0;i<len;i++) b[i]=((2*b[i]%Q-tp[i])%Q+Q)%Q;
	}
}

void SQR(LL*a,LL *b,int len){
	static LL g[M],tp[M],inv_g[M];
	if(len==1) b[0]=1;
	else{
		int i;
		SQR(a,b,len>>1);
		int N=len<<1;
		for(i=0;i<(len>>1);i++) g[i]=b[i]%Q;
		for(;i<N;i++) g[i]=b[i]=0;
		for(i=0;i<N;i++) inv_g[i]=0;
		INV(g,inv_g,len);
		
		for(i=0;i<len;i++) tp[i]=a[i];
		for(;i<N;i++) tp[i]=0;
		NTT(inv_g,N,1);
		NTT(tp,N,1);
		for(i=0;i<N;i++) tp[i]=inv_g[i]%Q*tp[i]%Q;
		NTT(tp,N,-1);
		for(i=0;i<len;i++) b[i]=(b[i]+tp[i])%Q*iv2%Q;
	}
}

int main(){

	int i,x;
	n=rd(),m=rd();
	for(i=1;i<=n;i++){
		x=rd();
		a[x]-=4;
		if(a[x]<0) a[x]+=Q;
	}
	a[0]++;
	for(n=2;n<=m;n<<=1);
	g=3;
	ig=pwr(3,Q-2);
	iv2=pwr(2,Q-2);
	
	SQR(a,b,n);

	b[0]++;
	INV(b,a,n);

	for(i=0;i<=m;i++) a[i]=(2LL*a[i])%Q;
	for(i=1;i<=m;i++) printf("%d
",a[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/acha/p/6474761.html