小朋友和二叉树

前言

一场考试六道题,就写了这一个,还好过了。

随便口胡一下就好了。

题目

洛谷

CF

讲解

一眼过去是个生成函数题,但是板子打了很久。

生成函数 \(F(n)\) 为权值为 \(n\) 时的方案数,\(G(n)\) 表示权值 \(n\) 是否存在,也就是说是个01串。

有关系式 \(F=F^2*G+1\),然后我们直接用求根公式,之后再选一个可以求出来的根即可。 \(\frac{1-\sqrt{1-4G}}{2G}\),用平方差公式变换一下保证求逆的多项式的零次项不为0。变换后答案为:

\(\frac{2}{1+\sqrt{1-4G}}\)

代码

考场代码,去注释版本。

//12252024832524
#include <cstdio> 
#include <cstring>
#include <algorithm>
#define TT template<typename T>
using namespace std;

typedef long long LL;
const int MAXN = 1 << 19 | 5;
const int MOD = 998244353;
const int PHI = 998244352;
const int G = 3;
const int GINV = 332748118;
int n,m;

LL Read()
{
	LL x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0') {if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9') {x = (x * 10) + (c ^ 48);c = getchar();}
	return x * f;
} 
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1) 
{
	if(x < 0) x = -x,putchar('-');
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x,T y){return x < 0 ? -x : x;}

int qpow(int x,int y)
{
	int ret = 1;
	while(y){if(y & 1) ret = 1ll * ret * x % MOD;x = 1ll * x * x % MOD;y >>= 1;}
	return ret;
}
int N,rev[MAXN];
void pre(int x)
{
	N = 1;int l = -1;
	while(N <= x) N <<= 1,l++;
	for(int i = 1;i < N;++ i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << l);
}
int Add(int x){if(x >= MOD) x -= MOD;return x;}
int Del(int x){if(x < 0) x += MOD;return x;}
void NTT(int *a,int opt)
{
	for(int i = 0;i < N;++ i) if(i < rev[i]) swap(a[i],a[rev[i]]);
	for(int i = 1;i < N;i <<= 1)
	{
		int w = qpow(opt == 1 ? G : GINV,PHI / (i << 1));
		for(int j = 0,p = i << 1;j < N;j += p)
		{
			int mi = 1;
			for(int k = 0;k < i;++ k,mi = 1ll * mi * w % MOD)
			{
				int X = a[j+k],Y = 1ll * mi * a[i+j+k] % MOD;
				a[j+k] = Add(X+Y);
				a[i+j+k] = Del(X-Y);
			}
		}
	}
	if(opt == -1)
	{
		int inv = qpow(N,MOD-2);
		for(int i = 0;i < N;++ i) a[i] = 1ll * a[i] * inv % MOD;
	}
}
int h[MAXN];
void polyinv(int *f,int *g,int len)//对f求逆,逆为g 
{
	if(len == 1)
	{
		g[0] = qpow(f[0],MOD-2);
		return;
	}
	polyinv(f,g,(len+1)>>1);
	pre(len<<1);
	for(int i = 0;i < len;++ i) h[i] = f[i];
	for(int i = len;i < N;++ i) h[i] = 0;
	NTT(h,1);
	NTT(g,1);
	for(int i = 0;i < N;++ i) g[i] = ((2ll * g[i] - 1ll * h[i] * g[i] % MOD * g[i]) % MOD + MOD) % MOD;
	NTT(g,-1);
	for(int i = len;i < N;++ i) g[i] = 0;
}
int a[MAXN],b[MAXN];
void polysqrt(int *f,int *g,int len)
{
	if(len == 1)
	{
		g[0] = 1;
		return;
	}
	polysqrt(f,g,(len+1)>>1);
	//求2g'的逆
	memset(b,0,sizeof(b));
	for(int i = 0;i < len;++ i) a[i] = Add(g[i]*2);
	polyinv(a,b,len);
	pre(len<<1);
	//求f+g'^2 
	for(int i = 0;i < len;++ i) a[i] = g[i];
	for(int i = len;i < N;++ i) a[i] = 0;
	NTT(a,1);
	for(int i = 0;i < N;++ i) a[i] = 1ll * a[i] * a[i] % MOD;
	NTT(a,-1);
	for(int i = 0;i < len;++ i) a[i] = Add(a[i] + f[i]);
	for(int i = len;i < N;++ i) a[i] = 0;
	//the last step
	NTT(a,1);
	NTT(b,1);
	for(int i = 0;i < N;++ i) g[i] = 1ll * a[i] * b[i] % MOD;
	NTT(g,-1);
	for(int i = len;i < N;++ i) g[i] = 0;
}
int ff[MAXN],gg[MAXN],ans[MAXN];

int main()
{
//	freopen("data.in","r",stdin);
//	freopen("mine2.out","w",stdout);
	n = Read(); m = Read();
	for(int i = 0;i < n;++ i) 
	{
		int val = Read();
		if(val <= m) ans[val] = MOD-4;
	}
	ans[0] = 1;
	polysqrt(ans,ff,m+1);
	ff[0]++;
	polyinv(ff,gg,m+1);
	pre(m<<1);
	for(int i = 0;i < N;++ i) ans[i] = 0;
	ans[0] = 2;
	NTT(ans,1);
	NTT(gg,1);
	for(int i = 0;i < N;++ i) ans[i] = 1ll * ans[i] * gg[i] % MOD;
	NTT(ans,-1);
	for(int i = 1;i <= m;++ i) Put(ans[i],'\n');
	return 0;
}
posted @ 2021-03-04 21:33  皮皮刘  阅读(48)  评论(0编辑  收藏  举报