JZOJ 4647 寻找 【NOIP2016提高A组模拟7.17】

寻找

题目大意

给出你一棵根节点为 1 的,共有n个点的树,现在给出除了1以外其他n-1节点的父亲。
现在给出你一个程序

starting_time是一个容量为n的数组
current_time = 0
dfs(v):        
       current_time = current_time + 1        
       starting_time[v] = current_time        
       将children[v]的顺序随机排列 (每个排列的概率相同)        
       // children[v]v的直接儿子组成的数组        
       for u in children[v]:               
               dfs(u)

求每一个点starting_time的期望值。

输入格式

第一行一个数N,表示节点数
第二行N-1个数,第i个数表示节点i+1的父节点。

输出格式

一行N个小数,第i个数表示starting_time[i]的期望值。

样例输入

7
1 2 1 1 4 4

样例输出

1.0 4.0 5.0 3.5 4.5 5.0 5.0

数据范围

对于30%的数据,N<=1000
对于100%的数据,N<=100000

题解

假设我们已经知道了starting_time[ u ],我们简写成Su
设点 u 的一个儿子为v
如果我们想要知道 Sv ,那我们就需要知道在遍历到点 v 之前,u的哪些其他子树已经被遍历过了。

我们设第 i 种选择子树(是否遍历)方案的期望值为Ki,则假设当前选到第 j 棵子树,1~~j-1的子树已经选完,有 m 种选择方案,则当前的点v的期望值 F Su+ 1 +{{\sum_{i=1}^{m}K_i}\over m}$。

现在我们对第j棵子树进行分类讨论。
如果不选第 j 棵子树,则有m种方案,期望和为mi=1Ki
如果选择第 j 棵子树,则也有m种方案,期望和为mi=1(Ki+Sizej)
其中 Sizej 表示以 j 为根节点的子树的大小(有多少个节点)。

所以由选完1~~j-1的子树到选完1~~ j 的子树的过程中,新的F= Su + 1 +mi=1Ki+mi=1(Ki+Sizej)m+m
化简得
F = F +Sizej2
所以最后

Sv = Su + 1 +k1i=1Sizei2(假设点 u k个儿子)

Sv = Su + 1 +SizeuSizev12

做一次递归并求期望值即可,一开始要预处理 Size 数组。

Code(Pascal)

var
    qw:array[0..100100] of extended;
    bj:array[0..100100,1..2] of longint;
    fa,en,size:array[0..101000] of longint;
    n,m,j,k,l,i,o,p:longint;
procedure qsort(l,r:longint);
    var
        i,j,m:longint;
    begin
        i:=l;
        j:=r;
        m:=bj[(l+r) div 2,1];
        repeat
            while bj[i,1]<m do inc(i);
            while bj[j,1]>m do dec(j);
            if i<=j then
            begin
                bj[0]:=bj[i];
                bj[i]:=bj[j];
                bj[j]:=bj[0];
                inc(i);
                dec(j);
            end;
        until i>j;
        if l<j then qsort(l,j);
        if i<r then qsort(i,r);
    end;
procedure dg(o:longint);
    var
        xcqw:extended;
        i:longint;
    begin
        for i:=en[o-1]+1 to en[o] do
        begin
            dg(bj[i,2]);
            size[o]:=size[o]+size[bj[i,2]];
        end;
        inc(size[o]);
    end;
procedure bl(o:longint);
    var
        i:longint;
    begin
        for i:=en[o-1]+1 to en[o] do
        qw[bj[i,2]]:=qw[o]+(size[o]-size[bj[i,2]]-1)/2+1;
        for i:=en[o-1]+1 to en[o] do
        bl(bj[i,2]);
    end;
begin
    readln(n);
    for i:=2 to n do
    begin
        read(fa[i]);
        bj[i-1,1]:=fa[i];
        bj[i-1,2]:=i;
        inc(en[fa[i]]);
    end;
    qsort(1,n-1);
    qw[1]:=1;
    for i:=2 to n do
    en[i]:=en[i-1]+en[i];
    dg(1);
    bl(1);
    for i:=1 to n do
    write(qw[i]:0:1,' ');
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值