对于 pass 1, 你把他考虑成 的形式, 于是每次操作的贡献就是 , 那么答案就是 .
对于 pass 2, 首先由全概率公式 . 那么我们考虑固定 , 求出 . 其实直接求这个有点麻烦, 强化一下条件, 我们求 , 最后后缀和即可取得 .
设 表示共 个叶结点, 树深度为 时的概率. 对于二叉树我们有一种经典的考虑子结构的方式, 即考虑左子树的信息. 对于此题, 我们考虑左子树 (相对于根结点来说) 的叶结点数量 . 那么有 . 其中 为全树的叶子个数, , 分别为左, 右子树的深度, 为左子树的叶结点个数. 是对于一个有 个叶子的二叉树, 有 个结点在左子树的概率, which 与 无关. 至于为什么是 , 你考虑操作次数为 即可.
#include <bits/stdc++.h>
using namespace std;
typedef double db;
int Q, N;
db f[200][200];
signed main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> Q >> N;
cout << fixed;
cout << setprecision(6);
if (Q == 1) {
db ans = 0;
for (int i = 2; i <= N; ++i) {
ans += 2.0 / i;
}
cout << ans << "\n";
} else if (Q == 2) {
f[1][0] = f[2][1] = f[3][2] = 1;
for (int i = 4; i <= N; ++i) {
for (int j = 1; j < i; ++j) {
for (int k = 0; k < j; ++k) {
for (int l = 0; l < i - j; ++l) {
f[i][max(k, l) + 1] += f[j][k] * f[i - j][l] / (i - 1);
}
}
}
}
db ans = 0;
for (int i = N; i >= 1; --i) {
f[N][i] += f[N][i + 1];
}
for (int i = 1; i < N; ++i) {
ans += f[N][i];
}
cout << ans << "\n";
}
return 0;
}