CF643E Bear and Destroying Subtrees (期望DP)

洛谷:题目链接
首先要确认这是一个期望DP.
线性性质就不必说了.
设f[x][i]表示以x为根,(dep[x_{son}] <= h)的概率
那么答案就是.(sum_{h = 1}^{MAX\_H}h * (f[x][h] - f[x][h - 1]))
考虑如何更新.
显然,可以通过(x_{son})转移,那么子节点(v = son_x)有两种情况,一个是存在边,对(f[x][h])贡献(1/2 * f[v][h - 1])的概率,二十不存在该边,概率那么就是(1/2)
然后就成了(f[x][h] = prod_{v = son_x}(1/2 + 1/2 * f[v][h - 1]))
更新的时候暴力更新即可,一直往上直到根节点.除掉以前的项,乘上新的项即可.
但是如果深度特别大怎么办,注意题目中的有精度误差,那么到了很大的数就会比(1e-6)小,这个时候精度达到了,不用继续.这里选择取(Max\_H = 60).
CODE

#include <iostream>
#include <cstdio>
const int maxN = 5e5 + 7;
const int maxH = 60;

int n,fa[maxN];
double f[maxN][maxH];

inline int read() {
	int x = 0,f = 1;char c = getchar();
	while(c < '0' || c > '9' ) {if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
	return x * f;
}

int main() {
	int n = 1,T = read(),opt,x;
	for(int i = 0;i < maxH;++ i) f[1][i] = 1;
	while(T --) {
		opt = read();x = read();
		if(opt == 1) {
			fa[++ n] = x;
			for(int i = 0;i < maxH;++ i) 
				f[n][i] = 1;
			double tmp1 = f[x][0],tmp2;
			f[x][0] *= 0.5;
			for(int Fa = fa[x],i = 1; Fa && i < maxH; Fa = fa[x = Fa],++ i)
            {
                tmp2 = f[Fa][i];
                f[Fa][i] /= 0.5 + 0.5 * tmp1;
                f[Fa][i] *= 0.5 + 0.5 * f[x][i-1];
                tmp1 = tmp2;
        	}
		}
		else {
			double ans = 0;
			for(int i = 1;i < maxH;++ i) 
			ans += (f[x][i] - f[x][i - 1]) * i;
			printf("%.10lf
",ans);
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/tpgzy/p/9691360.html