[Violet 5]列队春游
[Violet 5]列队春游 题解
这道题是一道期望好题,要用到 期望 + 组合数。
推导
因为 期望具有可加性(期望线性),所以我们可以分开计算每一个学生的期望视野距离,再求和。
每一个学生的期望视野距离可以直观地表示为:
其中:
-
\(ans\) 表示(任何)一个学生的期望视野距离(我们要做的是将每一个学生的 \(ans\) 求和);
-
\(L\) 表示对于(任何)一个学生,队伍的所有排列中 可能的所有视野距离中的 任意 一个。
这个式子形式为:
其实就是期望的基本计算公式。
更深一层想,任一 \(L > i\) 都会对这次(\(i\))的结果造成影响,所以又可以得到:
现在求概率,方法为 \(\frac{符合条件方案数}{总方案数}\)。设对于这个学生(♂),有 \(k\) 名学生的身高不低于他(不包括他本人)。
-
总方案数:这 \(k + 1\) 个人随便放的方案数为 \(A_{n}^{k + 1}\)。
-
符合条件方案数:
-
首先,这 \(k\) 个比他高或等于他的身高(会遮挡他的视线)的人不能放在他前面 \(i - 1\) 个位置(注意一定是 \(i - 1\),下图辅助理解),方案数为 \(A _{n - i}^{k}\);
^ | 11 2 | 2 4 | | 对于第6个人("/"),视野距离为4,所以他的前面有 | | / | | (4 - 1 = )3个人比他低。 | 1 | / 3 | | 6 | | | / | | 1 | 4 | | | | / 2 | | | | 3 | | | | | 2 / 1 | | 1 | | | 1 1 | | 1 | | | | 1 | / | | | | | | | | | | | | | | | | | | / | | | | | | | | | | | | | | | | | | 1 / | | | | | | | | | | | | | | | | | | | / | | | | | | | | | | | | | -------------------------------------------------------------------> -
其次,这个人不能放在序列的前 \(i - 1\) 个位置,所以还有 \(n - i + 1\) 种放置方案。
-
所以最终得到一个式子:
下面开始爆拆:
到了这里我们发现不好拆了,怎么办?这时我们手中还有一大宝典:组合数的计算。
先把求和函数里面的内容展开得:
这里回顾死去的知识,我们知道 \(C_n^m = C_{n - 1}^m + C_{n - 1}^{m - 1}\)。这个式子本来是一个效率不高的组合数计算方法,但是在这道题目中,他发挥了大作用。
我们发现在这种形式下,没有办法直接用这个式子,那我们可以加上一项 \(C_{1}^{k + 2}\)。因为 \(k\) 表示的是一类人的个数,所以 \(k \ge 0 \Rightarrow (k + 2) \ge 2 > 1\),即 \(C_{1}^{k + 2}\) 值为 \(0\)。故加上后原式值不变,下面就是愉快的合并:
我们把这个式子带回 梦 开始的式子,会惊奇的发现,我们消掉了一层 \(for\) 循环,而且后面的约分非常爽:
上面实现了对概率的计算,直接求和就行了。其实概率本不能直接求和,但是在某些题目中是可以的(比如这道题和小魔女帕琪)。
至于 \(k\),我们可以预处理,直接 \(O(n^2)\) 暴力求就行了。
代码
#include <bits/stdc++.h>
#define ldbl long double
#define Maxn 305
using namespace std;
int n, h[Maxn], k[Maxn];
double ans;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> h[i];
}
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= n; j ++) {
if (i != j && h[j] >= h[i]) { // i != j
k[i] ++;
}
}
}
for (int i = 1; i <= n; i ++) {
ans = ans + (n + 1) * 1.0 / (k[i] + 2);
}
printf("%.2lf", ans);
return 0;
}

浙公网安备 33010602011771号