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;
}

猜你喜欢

转载自www.cnblogs.com/tpgzy/p/9691360.html