CodeForces - 123E Maze

Description

给你一棵树,边权都是 1,每一个点有一个是起点的概率和一个是终点的概率,你将以起点为根,开始在树上随机 dfs,每到一个点,就会将他的所有儿子随机打乱成序列,然后按照那个随机顺序走完,直到走到终点。求 dfs 从起点到终点的期望长度。

前言

MD 我是 SB,我要疯了。

Solution

由于是 DFS 序,假设我们求的是 x 到 y(y 是 x 的儿子)的路径期望,如果走到另外一个儿子 z,要再走 \(\mathtt{2*siz[z]}\) 才能会到 x。每个儿子在 y 的前面的概率为 \(\mathtt{\frac{1}{2}}\)。(因为要么是 y 在前,要么是 z 在前)所以每个 z 对于路径期望都会贡献 \(\mathtt{siz[z]}\)

所以 x 到 y 的路径期望是:\(\mathtt{siz[x]-siz[y]-1+1}\)。前面的 \(\mathtt{siz[x]-siz[z]}\) 就不多说了,后面减去一是因为多算了 x 这个节点,又加上一是因为 x 到 y 有一条边的距离,而这条路的经过概率是 1。

由此观之啊呸,如果我们要计算的是 y 到 x 的路径期望(定义同上),可以把 x 看作 y 的儿子,我们就可以直接套之前的结论,答案就是:\(\mathtt{siz[y]}\)

最后,我们发现如果计算 u 到 x 的路径期望(其中 u 可以是 y 子树中的任意一点),答案也是 \(\mathtt{siz[y]}\)。(就一层层累加就好了)

这样,我们的算法应运而出:枚举 x 作为终点,再枚举 x 的儿子 y 作为起始点所在子树的代表,这样就可以算出以 x 子树中的点为起点,x 为终点的路径期望。但是,我们还要计算以 x 子树外的点为起点,x 为终点的路径期望。(后面这个部分也用和之前一样的“作案手法”,将 x 的父亲看成 x 的儿子,又可以用之前那个结论直接求了 QwQ)

这样求解的时间复杂度应该是 \(\mathtt{O(n)}\) 级别的,毕竟一个人只有一个爸爸嘛。

Code

#include <cstdio>

const int N = 100005;

int n, cnt, head[N], dot[N << 1], nxt[N << 1], fa[N], siz[N];
double in[N], out[N], si, so, ans;

int read() {
    int x = 0, f = 1; char s;
    while((s = getchar()) < '0' || s > '9') if(s == '-') f = -1;
    while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
    return x * f;
}

void addEdge(const int u, const int v) {
    dot[++ cnt] = v, nxt[cnt] = head[u], head[u] = cnt;
}

void dfs(const int u) {
    siz[u] = 1;
    for(int i = head[u]; i; i = nxt[i]) {
        int v = dot[i];
        if(v == fa[u]) continue;
        fa[v] = u;
        dfs(v);
        siz[u] += siz[v]; in[u] += in[v];
    }
}

int main() {
    n = read();
    for(int i = 1; i < n; ++ i) {
        int u = read(), v = read();
        addEdge(u, v), addEdge(v, u);
    }
    for(int i = 1; i <= n; ++ i) {
        in[i] = read(), out[i] = read();
        si += in[i]; so += out[i];
    }
    for(int i = 1; i <= n; ++ i) in[i] /= si;
    dfs(1);
    for(int u = 1; u <= n; ++ u) {
        for(int i = head[u]; i; i = nxt[i]) {
            int v = dot[i];
            if(fa[u] == v) ans += (1 - in[u]) * (n - siz[u]) * out[u] / so;
            else ans += in[v] * siz[v] * out[u] / so;
        }
    }
    printf("%.11f\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/AWhiteWall/p/12692753.html