CodeForces 1517F Reunion

洛谷传送门

CF 传送门

典?

考虑枚举 \(r\),算有多少种方案使得,存在一个点,离它最近的黑点距离 \(> r\)

\(f_{u, i}\)\(u\) 子树内离 \(u\) 最近的黑点距离为 \(i\)。如果一个点子树中离它最近的黑点距离 \(> r\),那么它就已经满足子树的限制了,还需要满足子树外的限制。称这样的点为预备点

于是再设 \(g_{u, i}\)\(u\) 子树内离 \(u\) 最远的预备点距离为 \(i\)

转移不好同时考虑全部子结点,就模仿树形背包合并子树。

感觉挺像 CF735E Ostap and Tree 的。

code
// Problem: F. Reunion
// Contest: Codeforces - Contest 2050 and Codeforces Round 718 (Div. 1 + Div. 2)
// URL: https://codeforces.com/problemset/problem/1517/F
// Memory Limit: 256 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 310;
const ll mod = 998244353;

inline ll qpow(ll b, ll p) {
	ll res = 1;
	while (p) {
		if (p & 1) {
			res = res * b % mod;
		}
		b = b * b % mod;
		p >>= 1;
	}
	return res;
}

/*
f_{u, i} u 子树距离 u 最近的黑点距离为 i
g_{u, i} u 子树距离 u 最远的预备点距离为 i
*/

ll n, r, sz[maxn], f[maxn][maxn], g[maxn][maxn], ff[maxn], gg[maxn];
vector<int> G[maxn];

inline void upd(ll &x, ll y) {
	((x += y) >= mod) && (x -= mod);
}

void dfs(int u, int fa) {
	f[u][0] = g[u][0] = sz[u] = 1;
	for (int v : G[u]) {
		if (v == fa) {
			continue;
		}
		dfs(v, u);
		for (int i = 0; i < sz[u] + sz[v]; ++i) {
			ff[i] = f[u][i];
			gg[i] = g[u][i];
			f[u][i] = g[u][i] = 0;
		}
		for (int i = 0; i < sz[u]; ++i) {
			for (int j = 0; j < sz[v]; ++j) {
				upd(f[u][min(i, j + 1)], ff[i] * f[v][j] % mod);
				upd(j + 1 + i > r ? g[u][j + 1] : f[u][i], ff[i] * g[v][j] % mod);
				upd(j + 1 + i > r ? g[u][i] : f[u][j + 1], gg[i] * f[v][j] % mod);
				upd(g[u][max(i, j + 1)], gg[i] * g[v][j] % mod);
			}
		}
		sz[u] += sz[v];
	}
}

void solve() {
	scanf("%lld", &n);
	for (int i = 1, u, v; i < n; ++i) {
		scanf("%d%d", &u, &v);
		G[u].pb(v);
		G[v].pb(u);
	}
	ll ans = 0;
	for (r = 1; r <= n; ++r) {
		mems(f, 0);
		mems(g, 0);
		dfs(1, -1);
		for (int i = 0; i <= n; ++i) {
			ans = (ans + g[1][i]) % mod;
		}
	}
	ans = (ans + mod - 1) % mod;
	printf("%lld\n", ans * qpow(qpow(2, mod - 2), n) % mod);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2023-09-13 07:51  zltzlt  阅读(15)  评论(0编辑  收藏  举报