当前位置 : 主页 > 大数据 > 区块链 >

CF696B Puzzles 期望

来源:互联网 收集:自由互联 发布时间:2021-06-22
显然可以树形$dp$ 令$f[i]$表示$i$号节点的期望时间戳 不妨设$fa$有$k$个子节点,对于$i$的子节点$u$,它是第$j(1 \leqslant j \leqslant k)$个被访问的概率是相同的,为$\frac{1}{k}$ 当它作为第$j$个

显然可以树形$dp$

令$f[i]$表示$i$号节点的期望时间戳

不妨设$fa$有$k$个子节点,对于$i$的子节点$u$,它是第$j(1 \leqslant j \leqslant k)$个被访问的概率是相同的,为$\frac{1}{k}$

当它作为第$j$个子节点被访问时,需要从剩下的$k - 1$个节点中挑出$j - 1$个放到它前面,对每种情况的$sz$和取期望

考虑贡献法

一个节点$v$,会给第$j$个被访问的节点的贡献次数为$\binom{k - 2}{j - 2}$

总的贡献次数为$\binom{k - 1}{j - 1}$

因此,第$v$个节点对第$j$个被访问的节点的贡献为$\frac{j - 1}{k - 1} * sz[v]$

也就是说$u$节点在所有情况下需要被耽误的时间应该为$\sum\limits_{1 \leqslant i \leqslant k} \frac{i - 1}{k - 1} * \sum sz[v]$

其中,$v$表示除了$u$以外的所有子节点

化简一番,也就是$f[v] = f[fa] + 1 + \frac{1}{2} * \sum sz[v]$

$O(n)$即可

#include <map>
#include <set>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
namespace remoon {
    #define de double
    #define le long double
    #define ri register int
    #define tpr template <typename ra>
    #define rep(iu, st, ed) for(ri iu = st; iu <= ed; iu ++)
    #define drep(iu, ed, st) for(ri iu = ed; iu >= st; iu --)    
    #define gc getchar
    inline int read() {
        int p = 0, w = 1; char c = gc();
        while(c > 9 || c < 0) { if(c == -) w = -1; c = gc(); }
        while(c >= 0 && c <= 9) p = p * 10 + c - 0, c = gc();
        return p * w;
    }
}
using namespace std;
using namespace remoon;

#define sid 300050

de f[sid];
int n, sz[sid];
vector <int> son[sid];

inline void dfs(int o, int fa) {
    sz[o] = 1;
    for(auto cur : son[o])
    dfs(cur, o), sz[o] += sz[cur];
}

inline void dfs(int o) {
    for(auto cur : son[o]) {
        f[cur] = f[o] + 1 + (sz[o] - sz[cur] - 1) / 2.0;
        dfs(cur);
    }
}

int main() {
    n = read();
    rep(i, 2, n) son[read()].pb(i);
    dfs(1, 0); f[1] = 1; dfs(1);
    rep(i, 1, n) printf("%lf ", f[i]);
    return 0;
}
网友评论