1. 程式人生 > 其它 >CF280C Game on Tree

CF280C Game on Tree

傳送門

蒟蒻初學概率與期望

這道題感覺非常玄幻 (雖然在大佬眼裡只是一道水題)


思路

我們設 \(f_i\) 表示 \(i\) 被刪除時選擇了 \(i\) 的次數

顯然 \(f_i=0/1\)

那麼題目要求的其實就是 \(E(\sum f_i)\)

而有因為期望滿足可加性

因此我們考慮求單個點的貢獻 \(E(f_i)\)

顯然,只有在恰好選到 \(i\) 點時,它才會有貢獻,且為恰好選到 \(i\) 的概率

這就要求我們之前都不能選擇 \(i\) 的祖先結點

那它的概率怎麼算?一個很妙的想法,就是將樹上的結點轉化成一個序列,而選點就是每次選擇一個最前面的數,將它以及它子樹內的數都去掉

那麼要恰好選擇到 \(i\)

,就要求 \(i\) 排在它所有祖先的前面

根據排列組合,這個概率顯然是 \(\frac{1}{dep_i}\)\(dep_i\) 表示 \(i\) 的深度,也就是 \(i\) 祖先樹 +1)

最後將所有都加起來即可


程式碼

#include<iostream>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#define LL long long
inline int reads()
{
    int sign = 1, re = 0; char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') sign = -1; c = getchar();}
    while('0' <= c && c <= '9'){re = re * 10 + (c - '0'); c = getchar();}
    return sign * re;
}
int n, cnt;
double ans;
struct Node
{
    int to, next;
}r[200005]; int he[100005];
inline void dfs(int now, int de, int fa)
{
    ans += 1.0 / de;
    for(int i = he[now]; i; i = r[i].next)
        if(r[i].to != fa) dfs(r[i].to, de + 1, now);
}
signed main()
{
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    n = reads();
    for(int i = 1; i < n; i++)
    {
        int u = reads(), v = reads();
        r[++cnt] = (Node){v, he[u]}, he[u] = cnt;
        r[++cnt] = (Node){u, he[v]}, he[v] = cnt;
    }
    dfs(1, 1, 0);
    printf("%.7lf", ans);
    return 0;
}