CodeForces 1517F Reunion
典?
考虑枚举 \(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;
}