[Codeforces 697D] Puzzles (期望)

Codeforces - 697D

给定一棵树,从1开始,按DFS的方式访问这棵树
每次从父亲节点随机访问儿子,问每个节点被访问到的时间的期望


设父亲节点的期望是 E,它有 n个儿子
其某个儿子是第 i次被访问到的,概率为 1n
设有个兄弟在它之前被访问了,其概率为 (i1)(n2)!(n1)!
他对期望的贡献为 (i1)(n2)!(n1)!size ,size为它的子树的大小
这样所有兄弟的贡献和就为 (i1)(n2)!(n1)!S ,S为兄弟子树的大小
所以排在 i位的期望即为 1n(i1n1S+E+1)
再把 i=1…n的期望加起来,即为 E+1+S2

还可以换一个角度思考:
对于随机产生的一个数列,对于某个儿子,其兄弟在其前面的概率为 12
所以这个兄弟对期望的贡献为 size2 ,所有兄弟加起来即为 S2
所以期望即为 E+1+S2

#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <map>
#include <set>
#include <queue>
using namespace std;
typedef pair<int,int> Pii;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DBL;
typedef long double LDBL;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Sqr(a) ((a)*(a))

const int maxn=1e5+10;
const DBL eps=1e-6;
struct Graph
{
    int ndn,edn,last[maxn];
    int u[maxn], v[maxn], nxt[maxn];
    void init(int _n){ndn=_n; edn=0; MST(last,-1);}
    void adde(int _u,int _v)
    {
        u[edn]=_u; v[edn]=_v;
        nxt[edn]=last[_u];
        last[_u]=edn++;
    }
};
DBL dp[maxn];
Graph G;
int size[maxn];
void dfs0(int);
void dfs1(int);

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
    #endif

    int N;
    scanf("%d", &N);
    G.init(N);
    for(int i=2; i<=N; i++)
    {
        int x;
        scanf("%d", &x);
        G.adde(x,i);
    }
    CLR(dp);
    dp[1]=1;
    dfs0(1);
    dfs1(1);
    for(int i=1; i<=N; i++) printf("%.1f ", dp[i]);
    return 0;
}

void dfs0(int u)
{
    size[u]=1;
    for(int e=G.last[u]; ~e; e=G.nxt[e])
    {
        int v=G.v[e];
        dfs0(v);
        size[u]+=size[v];
    }
}

void dfs1(int u)
{
    for(int e=G.last[u]; ~e; e=G.nxt[e])
    {
        int v=G.v[e];
        dp[v] = dp[u] + 1 + (size[u]-size[v]-1)/2.0;
        dfs1(v);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值