CF1517F Reunion(dp)
题目:洛谷CF1517F、CF1517F
题目描述:
给一棵\(n\)个点的树,每个点有\(\frac{1}{2}\)的概率被选中,一棵树的贡献为最大的\(r\)满足存在一个点,与它距离不超过\(r\)的点都被标记了
特别的,当没有点被标记时,记为\(0\)贡献;当所有点都被标记时,记为\(n\)贡献
求期望贡献对\(998244353\)取模
\(n \leq 300\)
蒟蒻题解:
可以先计算总贡献,再除以方案数
对于贡献\(r\),对于每个被标记的点,与它距离为\(r+1\)的点一定存在至少一个点没有被标记,也就是说我们可以用没被标记的点,把它们染成黑色,并把与它们距离不超过\(r+1\)的点的颜色也染成黑色,这样一定能使这棵树被染成黑色
直接算贡献为\(r\)的方案数不好求,考虑求贡献不超过\(r\)的方案数,这等价于没被标记的点覆盖与它们距离不超过\(r+1\)的点,能将这张图全部覆盖的方案数
考虑\(dp\)去求,当前子树如果有点还没被覆盖,只需要知道没被覆盖点的最深深度即可,否则只需要知道没被标记的点的最浅深度即可(用没被标记的点去覆盖别的点)
设\(f_{x,i}\)表示\(x\)子树内,所有点都被覆盖,最浅的没被标记的点与\(x\)的距离为\(i\)的方案数
设\(g_{x,i}\)表示\(x\)子树内,有点没有被覆盖,最深的没被覆盖的点与\(x\)的距离为\(i\)的方案数
然后树上背包即可
时间复杂度\(\Theta(n^3)\)
参考程序:
#include<bits/stdc++.h>
using namespace std;
#define Re register int
typedef long long ll;
const int N = 305, p = 998244353, pp = 499122177;
int n, cnt, s = 1, ans, hea[N], nxt[N << 1], to[N << 1], fa[N], dep[N], f[N][N], g[N][N], ff[N], gg[N], h[N];
inline int read()
{
char c = getchar();
int ans = 0;
while (c < 48 || c > 57) c = getchar();
while (c >= 48 && c <= 57) ans = (ans << 3) + (ans << 1) + (c ^ 48), c = getchar();
return ans;
}
inline void add(int x, int y)
{
nxt[++cnt] = hea[x], to[cnt] = y, hea[x] = cnt;
}
inline void dfs(int x)
{
for (Re i = hea[x]; i; i = nxt[i])
{
int u = to[i];
if (u == fa[x]) continue;
fa[u] = x;
dfs(u);
}
}
inline int max(int x, int y)
{
return x > y ? x : y;
}
inline int min(int x, int y)
{
return x < y ? x : y;
}
inline int inc(int x, int y)
{
x += y;
return x < p ? x : x - p;
}
inline void dfs1(int x, int y)
{
f[x][0] = g[x][0] = 1, dep[x] = 0;
for (Re i = 1; i <= y; ++i) f[x][i] = g[x][i] = 0;
for (Re i = hea[x]; i; i = nxt[i])
{
int u = to[i];
if (u == fa[x]) continue;
dfs1(u, y);
for (Re j = 0; j <= y; ++j) ff[j] = f[x][j], gg[j] = g[x][j], f[x][j] = g[x][j] = 0;
for (Re j = 0; j <= dep[x]; ++j)
for (Re k = 0; k <= dep[u]; ++k)
{
int v = min(j, k + 1), w = max(j, k + 1);
f[x][v] = (1ll * ff[j] * f[u][k] + f[x][v]) % p;
g[x][w] = (1ll * gg[j] * g[u][k] + g[x][w]) % p;
if (j + k + 1 <= y)
{
f[x][j] = (1ll * ff[j] * g[u][k] + f[x][j]) % p;
if (k < y) f[x][k + 1] = (1ll * gg[j] * f[u][k] + f[x][k + 1]) % p;
}
else
{
g[x][j] = (1ll * gg[j] * f[u][k] + g[x][j]) % p;
if (k < y) g[x][k + 1] = (1ll * ff[j] * g[u][k] + g[x][k + 1]) % p;
}
}
dep[x] = max(dep[x], min(dep[u] + 1, y));
}
}
int main()
{
n = ans = read();
for (Re i = 1; i < n; ++i)
{
int u = read(), v = read();
add(u, v), add(v, u);
}
dfs(1);
for (Re i = n - 1; i >= 0; --i, s = 1ll * s * pp % p)
{
dfs1(1, i);
for (Re j = 0; j <= i; ++j) h[i] = inc(h[i], f[1][j]);
if (i < n - 1) h[i + 1] = inc(h[i + 1] - h[i], p);
}
for (Re i = 0; i < n; ++i) ans = (1ll * h[i] * (i - 1 + p) + ans) % p;
ans = 1ll * ans * s % p;
printf("%d", ans);
return 0;
}

浙公网安备 33010602011771号