CF1517F Reunion(dp)

题目:洛谷CF1517FCF1517F

题目描述:

给一棵\(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;
}
posted @ 2021-05-08 21:09  clfzs  阅读(123)  评论(0)    收藏  举报