首先很好想到要用树形 \(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;
}
标签:sz,nxt,int,题解,void,CF696B,Puzzles,fa,dp
From: https://www.cnblogs.com/chang-an-22-lyh/p/18062866/cf696b-tj