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\n",ans);
}
}
return 0;
}