[CF696B] Puzzles 题解

首先很好想到要用树形 \(dp\)

然后设 \(dp_i\) 为遍历到第 \(i\) 个点的期望时间,\(sz_i\) 代表 \(i\) 的子树大小。

发现有转移方程:

\[dp_i=dp_{fa_i}+1+\sum\limits_{j\in fa_i且j\ne i}sz_j\times q \]

其中 \(q\) 为一个常数,代表在排列中 \(j\)\(i\) 前的概率。

很容易发现 \(q=\frac{1}{2}\)

于是转移方程可优化为:

\[dp_i=dp_{fa_i}+1+\frac{sz_{fa_i}-1-sz_i}{2} \]

时间复杂度 \(O(n)\)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll p=998244353;
const int N=100005;
int n,m,sz[N];
double dp[N];
int h[N],to[N],nxt[N];
void add(int x,int y){
    to[++m]=y;
    nxt[m]=h[x];
    h[x]=m;
}void dfs1(int x){
    for(int i=h[x];i;i=nxt[i]){
        dfs1(to[i]);
        sz[x]+=sz[to[i]];
    }sz[x]++;
}void dfs2(int x){
    for(int i=h[x];i;i=nxt[i]){
        dp[to[i]]=dp[x]+1+1.0*(sz[x]-1-sz[to[i]])/2.0;
        dfs2(to[i]);
    }
}int main(){
    cin>>n;
    for(int i=2;i<=n;i++){
        int fa;
        cin>>fa;
        add(fa,i);
    }dfs1(1);
    dp[1]=1;
    dfs2(1);
    for(int i=1;i<=n;i++)
        printf("%.1lf ",dp[i]);
    return 0;
}
posted @ 2024-03-09 16:04  长安一片月_22  阅读(4)  评论(0编辑  收藏  举报