CF1010Fツリー(チェーン・パーティション)(パーティションFFT)(ツリー上のDSU)

CF1010Fツリー

まず、この質問は、バイナリツリーを行うことができますされていません

トピックは、すべての人の息子よりも大きくなければならない、各の配布ポイントに変換することができる量のポイントを必要とします [ 0 , x ] [0、x]は 重み、最終値とのサブツリー

コレクションのサイズのわずか数このプログラムは
あります ( x + S 1 S 1 ) \ binom {X + S-1} {S-1}

質問は、ツリーの統計情報のサイズに変換され、 k K 接続されたブロックの数
既に n 2 N ^ 2 d p DP アップ

アカウントAに撮ります d p DP 最大寸法です s i z e [ u ] サイズ[U] 、月 d s u   o n   t r e e \ツリー上のDSU \
光の全て息子 s i z e サイズ 、とは、 n l o g ( n ) nlog(n)は であり
、次いで合成光が激しい息子によってマージされたパーティション内の各ノードとすることができます F F T FFT 、この部分の複雑さであります O ( n l o g ( n ) 3 ) O(nlog(n)は^ 3)

そう、マージどのように重鎖を検討 f u f_u 最終的な答えとして、 g u g_u その答えは、光の唯一の息子を検討している
(ここで f , g F、G )生成関数の後に書かれています
f u = g u ( f u + 1 + 1 ) = g u ( ( g u + 1 ( f u + 2 + 1 ) + 1 ) f_u = g_u(F_ {U + 1} +1)= g_u((G_ {U + 1}(F_ {U + 2} +1)+1)
何の再息子がない場合を考慮すると f = g F = G
次に、点 u f F として見ることができます g u + g u g u + 1 + g u g u + 1 g u + 2 + . . . g_u + g_u * G_ {U + 1} + g_u * G_ {U + 1} * G_ {U + 2} +··· あなたは、分割統治することができます F F T FFT
この部分の複雑さは、任意の天然あります n l o g ( n ) 3 nlog(n)は^ 3 、そして最終的に組み合わせの数でそれを頼りに


#include<bits/stdc++.h>
#define cs const
using namespace std;
typedef long long ll;
cs int N = 1e5 + 5;
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
int ksm(int a, int b){ int ans = 1; for(;b;b>>=1,a=mul(a,a)) if(b&1) ans = mul(ans, a); return ans; }
void Mul(int &a, int b){ a = mul(a, b); }
void Add(int &a, int b){ a = add(a, b); }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
#define pb push_back
#define poly vector<int>
poly a[N]; int inv[N];
void Cout(poly tt){
	for(int i = 0; i <tt.size(); i++) cout <<tt[i] <<" ";
	cout <<'\n';
}
namespace Poly{
	int bit, up, rev[N << 2];
	void init(int deg){
		up = 1; bit = 0; while(up <= deg) up <<= 1, ++bit;
		for(int i = 0; i < up; i++) rev[i] = (rev[i>>1]>>1)|((i&1)<<bit-1); 
	}
	cs int C = 19;
	poly w[C+1];
	void prework(){
		for(int i = 1; i <= C; i++) w[i].resize(1<<i-1);
		int wn = ksm(3, (Mod-1)/(1<<C)); w[C][0] = 1;
		for(int i = 1; i < (1<<C-1); i++) w[C][i] = mul(w[C][i-1], wn);
		for(int i = C-1; i; i--) for(int j = 0; j < (1<<i-1); j++) w[i][j] = w[i+1][j<<1];	
	}
	void NTT(poly &a, int typ){
		for(int i = 0; i < up; i++) if(i < rev[i]) swap(a[i], a[rev[i]]);
		for(int l = 1, i = 1; i < up; i <<= 1, ++l)
			for(int j = 0; j < up; j += (i<<1))
				for(int k = 0; k < i; k++){
					int x = a[k+j], y = mul(w[l][k], a[k+j+i]);
					a[k+j] = add(x, y); a[k+j+i] = dec(x, y);
				}
		if(typ == -1){
			reverse(a.begin() + 1, a.end());
			for(int i = 0, inv = ksm(up, Mod-2); i < up; i++) a[i] = mul(a[i], inv);
		}
	}
	poly operator * (poly a, poly b){
		int deg = a.size() + b.size() - 1;
		init(deg); a.resize(up); b.resize(up);
		NTT(a, 1); NTT(b, 1);
		for(int i = 0; i < up; i++) Mul(a[i], b[i]);
		NTT(a, -1); a.resize(deg); return a;
	}
	poly operator + (poly a, poly b){
		int deg = max(a.size(), b.size()); a.resize(deg); b.resize(deg);
		for(int i = 0; i < deg; i++) a[i] = add(a[i], b[i]); return a; 
	}
	void Solve(int l, int r, poly &F, poly &G){
	 	if(l == r){ F = G = a[l]; return; } int mid = (l+r) >> 1;
	 	poly Fl, Fr, Gl, Gr;
	 	Solve(l, mid, Fl, Gl); Solve(mid+1, r, Fr, Gr);
	 	F = Fl * Fr; G = Gl + Fl * Gr;
	}
}
int n; ll K;
vector<int> v[N]; 
int sz[N], son[N], fa[N];
void pre_dfs(int u, int f){
	sz[u] = 1; 
	for(int i = 0; i < v[u].size(); i++){
		int t = v[u][i]; if(t == f) continue; 
		fa[t] = u; pre_dfs(t, u); sz[u] += sz[t];
		if(sz[t] > sz[son[u]]) son[u] = t;
	}
}
poly f[N];
poly calc(int u){
	for(int t = u; t; t = son[t]){
		for(int i = 0; i < v[t].size(); i++) if((v[t][i] ^ fa[t]) && (v[t][i] ^ son[t])) f[t] = calc(v[t][i]);
		if(f[t].empty()) f[t].pb(0); ++f[t][0]; f[t].insert(f[t].begin(), 0);
	}
	int k = 0; 
	for(int t = u; t; t = son[t]) swap(a[++k], f[t]);
	poly F, G; Poly::Solve(1, k, F, G); return G;
}
int main(){
	scanf("%d%lld", &n, &K); Poly::prework();
	inv[0] = inv[1] = 1;
	for(int i = 2; i <= n; i++) inv[i] = mul(Mod-Mod/i, inv[Mod%i]); 
	for(int i = 1; i < n; i++){
		int x, y; scanf("%d%d", &x, &y); v[x].pb(y); v[y].pb(x);
	} pre_dfs(1, 0); poly g = calc(1);
	int Binom = 1, ans = 0;
	for(int i = 1; i < g.size(); i++){
		Add(ans, mul(Binom, g[i])); Mul(Binom, mul((K+i)%Mod, inv[i])); 
	} cout << ans; return 0;
}
发布了610 篇原创文章 · 获赞 94 · 访问量 5万+

おすすめ

転載: blog.csdn.net/sslz_fsy/article/details/103358952