[Codeforces Round #250 (Div. 1) -E] The Child and Binary Tree


Codeforcesトランスポートゲート
洛谷トランスミッションゲート
タイトル翻訳
私たちの子供はコンピューター科学が大好きで、特に二叉樹が好きです.n n n個の互いに異なる正の整数を含むシーケンスc[1],c[2],.,c [ n ] c[1],c[2],...,c[n] c[1],c[2],...,c[n].点権付きの二叉木がすべての頂点を満たす重み値が集合{c[1],c[2],.,c[n]}{c[1],c[2],...,c[n]}{c[1],c[2],...,c[n]}にある場合、私たちの子供はそれを神と呼ぶ.そして、ポイント権付きツリーの重み値は、そのすべての頂点の重み値の総和であると考えています.整数m m mを与えて、任意のs(1≦s≦m)s(1lesle m)s(1≦s≦m)に対してs sの重み値の神二叉樹の個数を計算することができますか?どのような2本の二叉木が異なると見なされるかを理解するために、サンプルを参照してください.998244353 998244353 998244353 998244353の型取り後の値について答えを知る必要があります.
入力1行目は2 2 2個の整数n,m(1≦n≦1 0 5;1≦m≦1 0 5)n,m(1le nle 10^5;1le mle 10^5)n,m(1≦n≦105;1≦m≦105)である.2行目はn n n個のスペースで区切られた互いに異なる整数c[1],c[2],.,c [ n ] ( 1 ≤ c [ i ] ≤ 1 0 5 ) c[1],c[2],...,c[n](1\le c[i]\le 10^5) c[1],c[2],...,c[n](1≤c[i]≤105).
m m m m行を出力し、行ごとに整数が1つあります.i i行目は、i i i i神998244353(=7)について答えを出力してください× 17 × 2 23 + 1 = 7 × 17 × 223 + 1 998244353(=7\times 17\times 2^{23}+1=7×17×223+1 998244353(=7×17×223+1=7×17×223+1,質量数)型取り後の結果.
入出力サンプル
サンプル#1を入力:
2 3
1 2

出力サンプル#1:
1
3
9

サンプル#2を入力:
3 10
9 4 3

出力サンプル#2:
0
0
1
1
0
2
4
2
6
15

入力サンプル#3:
5 10
13 10 6 4 15

出力サンプル#3:
0
0
0
1
0
1
0
2
0
5

解題分析
各個別の点の生成関数を考慮すると,明らかにr(x)=Σi∈S x i r(x)=sum_である.{i\in S}x^i r(x)=∑i∈S​xi.
二叉木の構造は再帰的に形成できるので,1つのサブツリーのルートノードに対してその生成関数をF(x)F(x)F(x)F(x)であると明らかにF(x)=r(x)F 2(x)+1 F(x)=r(x)F^2(x)+1 F(x)=r(x)F(x)F(x)=r(x)F(x)+1(空のツリーの場合は単独で計算し,生成関数に入れないので,具体的にはいくつかのステップを押すと分かる).
次式を求めることによりF(x)=1±1−4 r(x)2 r(x)F(x)=frac{1pmsqrt{1−4 r(x)}{2 r(x)}F(x)=2 r(x)1±1−4 r(x)となる.
上の正負がどう取っても、下の2 r(x)2 r(x)2 r(x)は明らかに0 0 0次項がなく、逆を求めることができない.
そして,上下に1∓1−4 r(x)1mpsqrt{1−4 r(x)}1∓1−4 r(x)を同乗すると,F(x)=2 1∓1−4 r(x)F(x)=frac{ 2}{1mpsqrt{1−4 r(x)}F(x)=1∓1−4 r(x)2が得られるので,負の番号を取るとゼロ次項がなく,F(x)F(x)F(x)F(x)F(x)F(x)F(x)F(x)F(x)F(x))の0 0 0次項係数は1 1 1であるべきで,この条件を満たさない.したがって,最後の解は2 1+1−4 r(x)frac{2}{1+sqrt{1−4 r(x)}}1+1−4 r(x)2である.
次にルートをどのように開くかを考えます.F(x)=A(x)F(x)=sqrt{A(x)}F(x)=A(x)またはそのニュートン反復のループとする:F(x)=F 0(x)=F 0(x)−G(F 0(x))G’(F 0(x))F(x)=F_0(x)-frac{G(F_0(x)}{G′(F_0(x)}F(x)=F 0(x)=F 0(x)−G′(F 0(x))G(F 0(x)))=F 2(x)−A(x)=F^2(x)=F^2(x)=F^2(x)−A(x)=F(x)−A(x)=F(x)=F(x)=F(x)=F(x)=F(x)=F 0(x)=F 0(x)−F 0(x)−F 2(x)−A(x)−A(x)2 F 0(x)2(x)−A(x)2(x)2 F 0(x)2(x)F x)F(x)=F_0(x)-\frac{F_0^2(x)-A(x)}{2F_0(x)} F(x)=F0​(x)−2F0​(x)F02​(x)−A(x)​.
再帰的に処理すればよい.
コードは次のとおりです.
#include 
#include 
#include 
#include 
#include 
#include 
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 400500
#define ll long long
#define G 3
#define Ginv 332748118
#define MOD 998244353
template <class T>
IN void in(T &x)
{
	x = 0; R char c = gc;
	for (; !isdigit(c); c = gc);
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
}
IN int fpow(R int base, R int tim)
{
	int ret = 1;
	W (tim)
	{
		if (tim & 1) ret = 1ll * ret * base % MOD;
		base = 1ll * base * base % MOD, tim >>= 1;
	}
	return ret;
}
int n, m;
int a1[MX], a2[MX], b[MX], c[MX], d[MX], e[MX], f[MX], g[MX];
int r[MX], rev[MX], ans[MX];
namespace Poly
{
	IN void NTT(int *dat, R int len, R bool typ)
	{
		for (R int i = 1; i < len; ++i) if (rev[i] > i) std::swap(dat[rev[i]], dat[i]);
		R int seg, step, bd, cur, now, buf1, buf2, deal, base;
		for (seg = 1; seg < len; seg <<= 1)
		{
			base = fpow(typ ? G : Ginv, (MOD - 1) / (seg << 1)), step = seg << 1;
			for (now = 0; now < len; now += step)
			{
				deal = 1, bd = now + seg;
				for (cur = now; cur < bd; ++cur, deal = 1ll * deal * base % MOD)
				{
					buf1 = dat[cur], buf2 = 1ll * dat[cur + seg] * deal % MOD;
					dat[cur] = (buf1 + buf2) % MOD, dat[cur + seg] = (buf1 - buf2 + MOD) % MOD;
				}
			}
		}
		if (typ) return; int inv = fpow(len, MOD - 2);
		for (R int i = 0; i < len; ++i) dat[i] = 1ll * dat[i] * inv % MOD;
	}
	void Getinv(R int up, R int lg, int *ind, int *ans)
	{
		if (up == 1) return ans[0] = fpow(ind[0], MOD - 2), void();
		Getinv(up >> 1, lg - 1, ind, ans);
		int len = up << 1, half = up >> 1; lg++;
		for (R int i = 1; i < len; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << lg - 1);
		for (R int i = 0; i < len; ++i) a1[i] = a2[i] = 0;
		for (R int i = 0; i < half; ++i) a1[i] = ans[i];
		for (R int i = 0; i < up; ++i) a2[i] = ind[i];
		NTT(a1, len, 1), NTT(a2, len, 1);
		for (R int i = 0; i < len; ++i) a1[i] = (a1[i] * 2 % MOD - 1ll * a1[i] * a1[i] % MOD * a2[i] % MOD + MOD) % MOD;
		NTT(a1, len, 0);
		for (R int i = 0; i < up; ++i) ans[i] = a1[i];
	}
	IN void Getrt(R int up, R int lg, int *ind, int *ans)
	{
		if (up == 1) return ans[0] = 1, void();
		Getrt(up >> 1, lg - 1, ind, ans);
		int len = up << 1, half = up >> 1; lg++;
		for (R int i = 0; i < half; ++i) c[i] = ans[i] * 2 % MOD;
		Getinv(up, lg - 1, c, b);
		for (R int i = 1; i < len; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << lg - 1);
		for (R int i = 0; i < len; ++i) a2[i] = 0;
		for (R int i = half; i < len; ++i) a1[i] = 0;
		for (R int i = 0; i < half; ++i) a1[i] = ans[i];
		NTT(a1, len, 1);
		for (R int i = 0; i < len; ++i) a1[i] = 1ll * a1[i] * a1[i] % MOD;
		NTT(a1, len, 0);
		for (R int i = up - 1; i < len; ++i) a1[i] = 0;
		for (R int i = 0; i < up; ++i) a1[i] = (a1[i] + ind[i]) % MOD, a2[i] = b[i];
		NTT(a1, len, 1), NTT(a2, len, 1);
		for (R int i = 0; i < len; ++i) a1[i] = 1ll * a1[i] * a2[i] % MOD;
		NTT(a1, len, 0);
		for (R int i = 0; i < up; ++i) ans[i] = a1[i];
	}
	IN void solve(R int up, R int lg)
	{
		for (R int i = 0; i < up; ++i) d[i] = (MOD - 2 * r[i] % MOD * 2 % MOD) % MOD;
		d[0] = (d[0] + 1) % MOD; Getrt(up, lg, d, e); e[0] = (e[0] + 1) % MOD;
		Getinv(up, lg, e, f);
		for (R int i = 0; i < up; ++i) ans[i] = f[i] * 2 % MOD;
	}
}
int main(void)
{
	in(n), in(m); int foo, len = 1, lg = 0;
	for (R int i = 1; i <= n; ++i) in(foo), r[foo] = 1;
	for (; len <= m; len <<= 1, lg++);
	Poly::solve(len, lg);
	for (R int i = 1; i <= m; ++i) printf("%d
"
, ans[i]); }