codeforces基础题——#362(div2)D

来源:互联网 发布:深圳冰川网络 市场策划 编辑:程序博客网 时间:2024/05/22 18:51

#362(Div 2) D

题目大意: 给你一棵n个节点的树(1 <= n <= 100000), 根结点为1, 跑一遍dfs, 但每次dfs一个点的儿子时顺序是随机的, 然后问每个点在dfs序中出现位置的期望。我们举个栗子:


这里写图片描述

可能的dfs序有 : 1 2 3 4 5, 1 2 3 5 4, 1 3 4 5 2, 1 3 5 4 2所以他们出现位置的期望分别是 :    ( 1 + 1 + 1 + 1 ) / 4,  ( 2 + 2 + 5 + 5 ) / 4,  ( 3 + 3 + 2 + 2 ) / 4,    ( 4 + 5 + 3 + 4 )  / 4,    (5 + 4 + 4 + 3) / 4;即 : 1,3.5,  2.5,  4,  4 题解 :这题作为D题感觉也有些水这题第一眼反应可能有点蒙(woc, 期望, 什么玩意), 但仔细想想其实很好算, 我们假设y是x的子节点, 假设x点位置确定, 那么枚举除y点外x的其他儿子选或不选的所有情况就是y点在dfs序中位置的所有情况,我们在选y之前选了一个点就会使y在当前dfs序中的位置加上以这个点为根的子树大小, 而这些点每一个只有选或不选两种可能,所以在所有情况中每个点会选(情况总数 / 2) 次,所以他们的贡献的和是(x除去y所有儿子的子树大小 * 情况总数 / 2), 即期望是(x除去y所有儿子的子树大小 / 2), 即 (sz[x] - sz[y]) / 2, 考虑dp, dp[x] = dp[father[x]] + (sz[x] - sz[father[x]]) / 2 + 1; 即可
#include <cstdio>#include <cstring>using namespace std;struct Edge{    int to, next;}edge[100100];int head[100100], num = -1;void add_edge(int a, int b){    edge[++ num].to = b;    edge[num].next = head[a], head[a] = num;}double f[100100], sz[100100];void dfs(int x){    sz[x] = 1;    for (int i = head[x]; i != -1; i = edge[i].next){        dfs(edge[i].to);        sz[x] += sz[edge[i].to];    }}void dp(int x){    for (int i = head[x]; i != -1; i = edge[i].next){        f[edge[i].to] = f[x] + 1 + (sz[x] - sz[edge[i].to] - 1) / 2;        dp(edge[i].to);    }}int main(){    int n, x;    scanf("%d", &n);    memset(head, -1, sizeof(head));    for (int i = 2; i <= n; i ++){        scanf("%d", &x);        add_edge(x, i);    }    dfs(1); //printf("*");    f[1] = 1.0; dp(1);    for (int i = 1; i <= n; i ++) printf("%.1lf ", f[i]);    printf("\n");    return 0;}
0 0