题解 CF438E 【The Child and Binary Tree】

题目链接

Solution CF438E The Child and Binary Tree

题目大意:给定正整数集合 (c)(forall s in[1,m]),求出有多少个有根二叉树,满足每个点的点权都在集合 (c) 中,且所有点的点权之和为 (s)。答案对 (998244353) 取模。

NTT,多项式开根


分析:

我们尝试着搞一个生成函数出来,令 ([x^s]F(x)) 表示得到点权之和为 (s) 的方案数

转移就是一个树形背包,也就是卷积的形式

([x^s]F(x)=sum_{i=1}^{n}[x^{s-c_i}]F^2(x))

然后这个东西还是一个卷积

我们设一个 (G)(forall c_i in cquad[x^{c_i}]G(x)=1)

也就是说 (F-1 equiv F^2G quad (mod;x^m))(因为可能子树为空,所以我们要求 ([x^0]F(x)=1)

代入求根公式,我们要求的就是这个 (F equiv frac{1 pm sqrt{1-4G}}{2G} quad (mod;x^m))

但是 (G) 的常数项为 (0),在模 (x^m) 意义下没有乘法逆

做一点变形

(Fequivfrac{(1-sqrt{1-4G})(1+sqrt{1-4G})}{2G(1+sqrt{1-4G})}equivfrac{2}{1+sqrt{1-4G}}quad(mod;x^m))

直接多项式开根,多项式求逆就可以了

萌新刚学多项式,有问题请多指教 /kel

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <vector>
#pragma GCC optmize(2)
using namespace std;
typedef long long ll;
constexpr int maxn = 4e5 + 100,mod = 998244353,G = 3,invG = 332748118,inf = 0x7fffffff;
constexpr inline int add(const int a,const int b){return (a + b) % mod;}
constexpr inline int sub(const int a,const int b){return (a - b + mod) % mod;}
constexpr inline int mul(const int a,const int b){return (1ll * a * b) % mod;}
inline int qpow(int base,int b){
	int res = 1;
	while(b){
		if(b & 1)res = mul(res,base);
		base = mul(base,base);
		b >>= 1;
	}
	return res;
}
inline int inv(const int x){return qpow(x,mod - 2);}
struct IO{//-std=c++11,with cstdio and cctype
	private:
		static constexpr int ibufsiz = 1 << 20;
		char ibuf[ibufsiz + 1],*inow = ibuf,*ied = ibuf;
		static constexpr int obufsiz = 1 << 20;
		char obuf[obufsiz + 1],*onow = obuf;
		const char *oed = obuf + obufsiz;
	public:
		inline char getchar(){
			#ifndef ONLINE_JUDGE
				return ::getchar();
			#else
				if(inow == ied){
					ied = ibuf + sizeof(char) * fread(ibuf,sizeof(char),ibufsiz,stdin);
					*ied = '';
					inow = ibuf;
				}
				return *inow++;
			#endif
		}
		template<typename T>
		inline void read(T &x){
			static bool flg;flg = 0;
			x = 0;char c = getchar();
			while(!isdigit(c))flg = c == '-' ? 1 : flg,c = getchar();
			while(isdigit(c))x = x * 10 + c - '0',c = getchar();
			if(flg)x = -x;
		}
		template <typename T,typename ...Y>
		inline void read(T &x,Y&... X){read(x);read(X...);}
		inline int readi(){static int res;read(res);return res;}
		inline long long readll(){static long long res;read(res);return res;}
		
		inline void flush(){
			fwrite(obuf,sizeof(char),onow - obuf,stdout);
			fflush(stdout);
			onow = obuf;
		}
		inline void putchar(char c){
			#ifndef ONLINE_JUDGE
				::putchar(c);
			#else
				*onow++ = c;
				if(onow == oed){
					fwrite(obuf,sizeof(char),obufsiz,stdout);
					onow = obuf;
				}
			#endif
		}
		template <typename T>
		inline void write(T x,char split = ''){
			static unsigned char buf[64];
			if(x < 0)putchar('-'),x = -x;
			int p = 0;
			do{
				buf[++p] = x % 10;
				x /= 10;
			}while(x);
			for(int i = p;i >= 1;i--)putchar(buf[i] + '0');
			if(split != '')putchar(split);
		}
		inline void lf(){putchar('
');}
		~IO(){
			fwrite(obuf,sizeof(char),onow - obuf,stdout);
		}
}io;
template <typename A,typename B>
inline void chkmin(A &x,const B &y){if(y < x)x = y;}
template <typename A,typename B>
inline void chkmax(A &x,const B &y){if(y > x)x = y;}

int tr[maxn << 1],len = 1;
struct poly : std::vector<int>{
	using std::vector<int>::vector;
	#define f (*this)
	inline void ntt(const int flg = 1){
		const int n = size();
		for(int i = 0;i < n;i++)
			if(i < tr[i])std::swap(f[i],f[tr[i]]);
		for(int p = 2;p <= n;p <<= 1){
			const int unit = qpow(flg == 1 ? G : invG,(mod - 1) / p);
			const int len = p >> 1;
			for(int k = 0;k < n;k += p){
				int now = 1;
				for(int l = k;l < k + len;l++){
					const int tt = mul(f[l + len],now);
					f[l + len] = sub(f[l],tt);
					f[l] = add(f[l],tt);
					now = mul(now,unit);
				}
			}
		}
		if(flg == -1){
			const int inv = ::inv(n);
			for(int i = 0;i < n;i++)f[i] = mul(f[i],inv);
		}
	}
	poly operator + (const poly &g)const{
		poly res;res.resize(size());
		for(unsigned int i = 0;i < size();i++)res[i] = add(f[i],g[i]);
		return res;
	}
	poly operator * (const poly &g)const{
		poly res;res.resize(size());
		for(unsigned int i = 0;i < size();i++)res[i] = mul(f[i],g[i]);
		return res;
	}
	poly operator * (const int g)const{
		poly res;res.resize(size());
		for(unsigned int i = 0;i < size();i++)res[i] = mul(f[i],g);
		return res;
	}
	poly operator - (const poly &g)const{
		poly res;res.resize(size());
		for(unsigned int i = 0;i < size();i++)res[i] = sub(f[i],g[i]);
		return res;
	}
	inline void print()const{
		fprintf(stderr,"siz=%d :",(int)size());
		for(int x : (*this))fprintf(stderr,"%d ",x);
		fprintf(stderr,"
");	
	}
	#undef f
};
inline poly calc(poly a,poly &&b){//2 * b - a * b ^ 2
	for(len = 1;len < a.size() + b.size() + b.size() - 2;len <<= 1);
	for(int i = 0;i < len;i++)
		tr[i] = (tr[i >> 1] >> 1) | ((i & 1) ? (len >> 1) : 0);
	a.resize(len);
	b.resize(len);
	a.ntt();
	b.ntt();
	poly &&res = b * 2 - a * b * b;
	res.ntt(-1);
	return res;
}
inline poly inv(const poly &x){
	if(x.size() == 1)return poly{inv(x[0])};
	poly tmp(x);
	tmp.resize((x.size() + 1) >> 1);
	tmp = calc(x,inv(tmp));
	tmp.resize(x.size());
	return tmp;
}
inline poly sqrt(const poly &x){
	if(x.size() == 1)return poly{1};
	poly t(x);t.resize((x.size() + 1) >> 1);t = sqrt(t);
	poly g(x);
	poly inv = t * 2;
	inv.resize(x.size());
	inv = ::inv(inv);
	for(len = 1;len < t.size() + t.size() + inv.size() - 2;len <<= 1);
	for(int i = 0;i < len;i++)
		tr[i] = (tr[i >> 1] >> 1) | ((i & 1) ? (len >> 1) : 0);
	t.resize(len);g.resize(len);inv.resize(len);
	t.ntt();g.ntt();inv.ntt();
	poly res = (t * t + g) * inv;
	res.ntt(-1);
	res.resize(x.size());
	return res;
}
int main(){
	const int n = io.readi(),m = io.readi();
	poly g;
	g.resize(1e5 + 1);
	for(int i = 1;i <= n;i++)g[io.readi()] = 1;
	g.resize(m + 1);

	for(unsigned int i = 0;i < g.size();i++)g[i] = sub(0,4 * g[i]);
	g[0] = add(g[0],1);
	g = sqrt(g);
	g[0] = add(g[0],1);
	g.resize(m + 1);
	g = inv(g);
	poly f;
	f.resize(m + 1);
	f[0] = 2;
	for(int len = 1;len < g.size() + f.size() - 1;len <<= 1);
	for(int i = 0;i < len;i++)tr[i] = (tr[i >> 1] >> 1) | ((i & 1) ? (len >> 1) : 0);
	f.resize(len);g.resize(len);
	f.ntt();g.ntt();
	poly ans = f * g;
	ans.ntt(-1);
	for(int i = 1;i <= m;i++)io.write(ans[i],'
');
	return 0;
}
原文地址:https://www.cnblogs.com/colazcy/p/14106681.html