「CF696B」Puzzle 题解 (期望与树形综合DP)
题目简介
给一颗树,按 \(dfs\) 序遍历并编号,对每个点求其编号的期望值。
分析
鄙人的想法与题解区稍微有点区别(尽管结论一样,过程却繁杂得多),希望不被大佬们嫌弃。
令\(f_x\)表示结点 \(x\) 的期望值,\(siz_x\)表示以 \(x\) 为根的子树大小,考虑当前结点为 \(x\) 怎么向其子节点 \(y\) 转移。
令 \(x\) 有 \(k\) 个儿子:
-
假设在 \(x\) 选择的第一个结点就是 \(y\) ,那么 \(f_y\) 将等于 \(f_x+1\),而概率是 \(\frac{1}{k}\);
-
假设在 \(x\) 选择的第一个结点不是 \(y\) ,第二个结点是 \(y\) ,那么 \(y\) 有 \((k-1)\) 种不同的编号,分别是 \(f_x+siz_{y'}+1(y'\ne y)\),因此总贡献为 \((k-1)\times f_x+\sum siz_{y'}(y'\ne y)+(k-1)\) ,每种的概率都是 \((1-\frac{1}{k})\times\frac{1}{k-1}\times\frac{1}{k-1}=\frac{1}{k-1}\times \frac{1}{k}\);
-
依此类推,假设 \(y\) 在第三个被选择,那么总贡献将为 \((k-2)\times f_x+2\times \sum siz_{y'}+(k-2)\),相应的概率均为 \(\frac{1}{k-2}\times \frac{1}{k}\);
-
\(\dots\)
综上,可以得到一个状态转移方程:
\[f_{y}=(f_x+1)\times \frac{1}{k}+\overset{k-1}{\underset{i=1}{\sum}}(f_x+\frac{\sum siz_{y'}(y'\ne y)}{n-i}+1)\times \frac{1}{k}
\]
这么去推肯定大大的\(\mbox{TLE}\),考虑化简。
\[\sum siz_{y'}(y'\ne y)=siz_x-siz_y-1
\]
\[f_{y}=(f_x+1)\times \frac{1}{k}+\overset{k-1}{\underset{i=1}{\sum}}(f_x+\frac{siz_x-siz_y-1}{n-i}+1)\times \frac{1}{k}
\]
\[f_{y}=(f_x+1)\times \frac{1}{k}+\overset{k-1}{\underset{i=1}{\sum}}(f_x+\frac{siz_x-siz_y-1}{i}+1)\times \frac{1}{k}
\]
\[f_{y}=f_x+1+\overset{k-1}{\underset{i=1}{\sum}}\frac{siz_x-siz_y-1}{i}\times \frac{1}{k}
\]
令 \(t=siz_x-siz_y-1\)
\[\overset{k-1}{\underset{i=1}{\sum}}\frac{t}{i}\times \frac{1}{k}=t\times\overset{k-1}{\underset{i=1}{\sum}}\frac{1}{i\times k}=t\times\frac{\frac{k(k-1)}{2}}{k(k-1)}=\frac{t}{2}
\]
由此得到转移:
\[f_y=f_x+\frac{siz_x-siz_y-1}{2}+1
\]
\(AC\ Code\)
#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
const int Maxn=1e5+5;
vector<int>tr[Maxn];
long double f[Maxn];
int siz[Maxn];
void dfs1(int x){
siz[x]=1;
for(auto y:tr[x]){
dfs1(y);
siz[x]+=siz[y];
}
}
void dfs2(int x){
for(auto y:tr[x]){
f[y]=f[x]+1.0*(siz[x]-siz[y]-1)/2+1;
dfs2(y);
}
}
int main(){
int n;cin>>n;
for(int i=2;i<=n;++i){
int x;cin>>x;
tr[x].push_back(i);
}
f[1]=1;
dfs1(1);dfs2(1);
for(int i=1;i<=n;++i)printf("%.7Lf ",f[i]);
return 0;
}