P3830 [SHOI2012]随机树
P3830 [SHOI2012]随机树
Solution
Problem 1
记有 \(n\) 个叶节点时叶节点平均深度的期望值为 \(f_n\)。
\[\begin{aligned}
f_{n} &= \frac{(n - 1)f_{n - 1} - f_{n - 1} + 2\times (f_{n - 1} + 1)}{n} \\
&= f_{n - 1} + \frac{2}{n}
\end{aligned}
\]
即:原来的叶节点期望深度和减去被展开点的期望深度加上新增点的期望深度再除以当前叶节点总数。
边界为 \(f_{1} = 0\)。
Problem 2
首先要对期望的公式足够熟悉。
\[E(x) = \sum\limits_{i = 1}^{+\infty}P(x \ge i)
\]
记 \(f_{i, j}\) 表示有 \(i\) 个叶节点时,树的深度 \(\ge j\) 的概率。
\[f_{i, j} = \sum\limits_{k = 1}^{i - 1}\frac{1}{i - 1}(f_{k, j - 1} + f_{i - k, j - 1} - f_{k, j - 1}\times f_{i - k, j - 1})
\]
那么题解里面一堆人问为什么要除个 \(i - 1\)。我觉得不应该看为什么除以 \(i - 1\),而该思考右边括号里的玩意儿加起来到底是什么,有什么含义?然后能看出左右子树叶节点数的分配在总数一定的情况下并不影响合起来合法的概率,这个 \(\frac{1}{i - 1}\) 就很显然了。
易知答案为
\[ans = \sum\limits_{i = 1}^{n - 1}f_{n, i}
\]
边界 \(f_{i, 0} = 1\)。
#include<bits/stdc++.h>
using namespace std;
const int N = 105;
int op, n;
double f[N][N];
int main()
{
scanf("%d %d", &op, &n);
if(op == 1)
{
double res = 0;
for(int i = 2; i <= n; ++i)
res += 2.0 / i;
printf("%.6lf\n", res);
}
if(op == 2)
{
for(int i = 0; i <= n; ++i)
f[i][0] = 1;
for(int i = 2; i <= n; ++i)
for(int j = 1; j < i; ++j)
{
for(int k = 1; k < i; ++k)
f[i][j] += f[k][j - 1] + f[i - k][j - 1] - f[k][j - 1] * f[i - k][j - 1];
f[i][j] /= i - 1;
}
double res = 0;
for(int i = 1; i < n; ++i)
res += f[n][i];
printf("%.6lf\n", res);
}
return 0;
}

浙公网安备 33010602011771号