1. 程式人生 > 其它 >「CF696B」Puzzle 題解 (期望與樹形綜合DP)

「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-----$$