[Codeforces 438E]The Child and Binary Tree(生成函数 + 多项式开平方)

Address

Meaning

  • 给定一个 n n 元正整数集合 S S
  • 对于任意的 1 i m 1\le i\le m
  • 求有多少棵不同(形态不同或点权不同)的点带权无标号有根二叉树的所有点权和为 i i (所有的点权都在集合 S S 内)
  • 1 n , m , S 1 0 5 1\le n,m,S内的元素\le10^5

Solution

  • 先列出 DP 式子: f [ i ] f[i] 表示点权和为 i i 的方案数, f [ 0 ] = 1 f[0]=1
  • f [ i ] = k S , k i j = 0 i k f [ j ] f [ i k j ] f[i]=\sum_{k\in S,k\le i}\sum_{j=0}^{i-k}f[j]f[i-k-j]
  • f f 的生成函数为 F ( x ) F(x) ,则
  • f [ i ] = k S , k i [ x i k ] F ( x ) 2 f[i]=\sum_{k\in S,k\le i}[x^{i-k}]F(x)^2
  • 再设生成函数
  • G ( x ) = k S x k G(x)=\sum_{k\in S}x^k
  • f [ i ] = k = 1 i [ x k ] G ( x ) [ x i k ] F ( x ) 2 = [ x i ] G ( x ) F ( x ) 2 f[i]=\sum_{k=1}^i[x^k]G(x)[x^{i-k}]F(x)^2=[x^i]G(x)F(x)^2
  • 于是再加上边界条件 f [ 0 ] = 1 f[0]=1 ,得
  • F ( x ) = 1 + G ( x ) F ( x ) 2 F(x)=1+G(x)F(x)^2
  • 解关于 F ( x ) F(x) 的一元二次方程得
  • F ( x ) = 1 ± 1 4 G ( x ) 2 G ( x ) F(x)=\frac{1\pm\sqrt{1-4G(x)}}{2G(x)}
  • 注意到 [ x 0 ] G ( x ) = 0 [x^0]G(x)=0 ,所以 G ( x ) 1 G(x)^{-1} 不存在,当 ± \pm + + 时分子的 0 0 次项不为 0 0 ,这样显然是没有意义的,所以
  • F ( x ) = 1 1 4 G ( x ) 2 G ( x ) = 2 1 + 1 4 G ( x ) F(x)=\frac{1-\sqrt{1-4G(x)}}{2G(x)}=\frac2{1+\sqrt{1-4G(x)}}
  • 使用多项式开平方 + 多项式求逆解决
  • 最后科普一下多项式开平方
  • 先假设你会多项式求逆
  • 考虑和多项式 exp 一样使用牛顿迭代求解
  • 大概就是我们要求一个多项式 G ( x ) F ( x ) (   m o d   x n ) G(x)\equiv \sqrt{F(x)}(\bmod x^n)
  • 也就是 G ( x ) 2 F ( x ) 0 (   m o d   x n ) G(x)^2-F(x)\equiv 0(\bmod x^n)
  • 根据牛顿迭代
  • x n + 1 = x n f ( x ) f ( x ) x_{n+1}=x_n-\frac{f(x)}{f'(x)}
  • 得到多项式开平方的迭代
  • G k + 1 ( x ) = G k ( x ) G k ( x ) 2 F ( x ) 2 G k ( x ) G_{k+1}(x)=G_k(x)-\frac{G_k(x)^2-F(x)}{2G_k(x)}
  • 其中 G k ( x ) G_k(x) 表示 F ( x ) F(x) x 2 k x^{2^k} 意义下的开平方
  • 其中 G 0 ( x ) = [ x 0 ] F ( x ) G_0(x)=\sqrt{[x^0]F(x)}
  • 迭代到 G k ( x ) G_k(x) 满足 2 k n 2^k\ge n 时,我们就求得了模 x n x^n 的开平方
  • 考虑复杂度,对模 x n x^n 开平方的复杂度 T ( n ) T(n) 满足
  • T ( n ) = T ( n 2 ) + O ( n log n ) T(n)=T(\frac n2)+O(n\log n)
  • T ( n ) = O ( n log n ) T(n)=O(n\log n)

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Step(i, a, b, x) for (i = a; i <= b; i += x)
#define Pow(k, n) for (k = 1; k < n; k <<= 1)

inline int read()
{
	int res = 0; bool bo = 0; char c;
	while (((c = getchar()) < '0' || c > '9') && c != '-');
	if (c == '-') bo = 1; else res = c - 48;
	while ((c = getchar()) >= '0' && c <= '9')
		res = (res << 3) + (res << 1) + (c - 48);
	return bo ? ~res + 1 : res;
}

template <class T>
inline void Swap(T &a, T &b) {a ^= b; b ^= a; a ^= b;}

const int N = 14e5 + 5, ZZQ = 998244353;

int n, m, cnt[N], rev[N], ff = 4, tot = 2, gg = 748683265, omega[N],
sqrtc[N], invc[N], tmp[N], invsq[N], pmt[N];

int qpow(int a, int b)
{
	int res = 1;
	while (b)
	{
		if (b & 1) res = 1ll * res * a % ZZQ;
		a = 1ll * a * a % ZZQ;
		b >>= 1;
	}
	return res;
}

void FFT(int n, int *a, int op)
{
	int i, j, k = n >> 1;
	For (i, 0, n - 1) if (i < rev[i]) Swap(a[i], a[rev[i]]);
	omega[n] = qpow(3, (ZZQ - 1) / n * (op == 1 ? 1 : n - 1));
	while (k)
		omega[k] = 1ll * omega[k << 1] * omega[k << 1] % ZZQ, k >>= 1;
	Pow(k, n)
	{
		int x = omega[k << 1];
		Step (i, 0, n - 1, k << 1)
		{
			int w = 1;
			For (j, 0, k - 1)
			{
				int u = a[i + j], v = 1ll * w * a[i + j + k] % ZZQ;
				a[i + j] = (u + v) % ZZQ;
				a[i + j + k] = (u - v + ZZQ) % ZZQ;
				w = 1ll * w * x % ZZQ;
			}
		}
	}
}

void getinv(int n, int *a, int *res)
{
	int i, k, ff = 4, gg = 748683265, tot = 2;
	res[0] = qpow(a[0], ZZQ - 2);
	Pow(k, n)
	{
		For (i, 0, ff - 1)
			rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << tot - 1);
		For (i, 0, (ff >> 1) - 1) pmt[i] = a[i];
		For (i, ff >> 1, ff - 1) pmt[i] = 0;
		For (i, ff >> 2, ff - 1) res[i] = 0;
		FFT(ff, pmt, 1); FFT(ff, res, 1);
		For (i, 0, ff - 1)
			res[i] = 1ll * res[i] * (2 - 1ll * pmt[i] * res[i] % ZZQ
			+ ZZQ) % ZZQ;
		FFT(ff, res, -1);
		For (i, 0, (ff >> 1) - 1) res[i] = 1ll * res[i] * gg % ZZQ;
		ff <<= 1; tot++;
		gg = 499122177ll * gg % ZZQ;
	}
	For (i, n, ff >> 1) res[i] = 0;
}

int main()
{
	int i, x, k;
	n = read(); m = read();
	For (i, 1, n) if ((x = read()) <= m) cnt[x] = ZZQ - 4;
	cnt[0] = sqrtc[0] = 1;
	Pow(k, m + 1)
	{
		For (i, 0, k - 1) tmp[i] = sqrtc[i];
		For (i, k, (k << 1) - 1) tmp[i] = 0;
		getinv(k << 1, tmp, invc);
		For (i, 0, ff - 1)
			rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << tot - 1);
		For (i, 0, (ff >> 1) - 1) tmp[i] = cnt[i];
		For (i, ff >> 1, ff - 1) tmp[i] = 0;
		FFT(ff, tmp, 1); FFT(ff, sqrtc, 1); FFT(ff, invc, 1);
		For (i, 0, ff - 1)
			sqrtc[i] = (sqrtc[i] - 499122177ll *
				(1ll * sqrtc[i] * sqrtc[i] % ZZQ - tmp[i] + ZZQ)
				% ZZQ * invc[i] % ZZQ + ZZQ) % ZZQ;
		FFT(ff, sqrtc, -1);
		For (i, 0, (ff >> 1) - 1) sqrtc[i] = 1ll * sqrtc[i] * gg % ZZQ;
		For (i, ff >> 1, ff - 1) sqrtc[i] = 0;
		ff <<= 1; tot++;
		gg = 499122177ll * gg % ZZQ;
	}
	For (i, m + 1, ff >> 1) sqrtc[i] = 0;
	sqrtc[0]++; invsq[0] = 499122177;
	getinv(m + 1, sqrtc, invsq);
	For (i, 1, m) printf("%d\n", 2 * invsq[i] % ZZQ);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/86417402