「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;
}

$$-----EOF-----$$

posted @ 2022-05-12 19:05  AlienCollapsar  阅读(29)  评论(1编辑  收藏  举报
// 生成目录索引列表 // ref: http://www.cnblogs.com/wangqiguo/p/4355032.html // modified by: zzq