链接
Description
给定有 \(n(n \le 10^5)\) 个点的树,每次操作等概率随机选取一个存在的节点删除他和他的子树,问期望的操作次数。
Solution
考虑转化题意。假设 \(c_i\) 表示某个节点被选到的次数(显然取值只有 \(0/1\)),题目相当于求 \(\sum c_i\) 的期望值。由期望的性质可得,\(E(\sum c_i) = \sum E(c_i)\)。进一步观察发现,由于 \(c_i \in \{0,1\}\),实际上 \(E(c_i)\) 等价于某个节点被选到的概率 \(p_i\)。
现在只需要求 \(\sum p_i\),只要某个节点的祖先均不在其之前被选到,那这个节点就会被选到。一个节点的祖先共有 \(dep_i-1\) 个(\(dep_i\) 表示 \(1\) 到 \(i\) 最短路径的点个数)。那么实际上我们只需要探讨操作选点序列中 \(i,fa_i, fa_{fa_i},\dots,1\) 的排列顺序,其余点不用管。一共 \(dep_i\) 个点,总共就有 \(dep_i!\) 种排列方式,其中 \(i\) 在第一位的方案总数为 \((dep_i-1)!\),所以 \(p_i=\dfrac{(dep_i-1)!}{dep_i!}=\dfrac{1}{dep_i}\)。
#include <bits/stdc++.h>
#define FASTIO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, r, l) for (int i = r; i >= l; i--)
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int N = 1e5+5, M = 5e5+5;
int n;
vector<int> G[N];
#define adde(u, v) G[u].push_back(v)
int dep[N];
void dfs(int x, int fa) {dep[x] = dep[fa]+1;for (auto y : G[x]) {if (y == fa) continue;dfs(y, x);}
}
int main() {FASTIO;cin >> n;rep(i, 2, n) {int u, v;cin >> u >> v;adde(u, v), adde(v, u);}dfs(1, 0);long double ans = 0;rep(i, 1, n) ans += 1.0/dep[i];cout << fixed << setprecision(20) << ans << '\n';return 0;
}
证明过程不会看了看题解。