[Violet 5]列队春游

[Violet 5]列队春游 题解

这道题是一道期望好题,要用到 期望 + 组合数。

推导

因为 期望具有可加性(期望线性),所以我们可以分开计算每一个学生的期望视野距离,再求和。

每一个学生的期望视野距离可以直观地表示为:

\[ans = \sum_{i = 1} ^ {n} i \times P(L = i) \]

其中:

  • \(ans\) 表示(任何)一个学生的期望视野距离(我们要做的是将每一个学生的 \(ans\) 求和);

  • \(L\)​ 表示对于(任何)一个学生,队伍的所有排列中 可能的所有视野距离中的 任意 一个。

这个式子形式为:

\[期望 = \sum_{i = 1} ^ {n} 结果 \times 概率 \]

其实就是期望的基本计算公式。

更深一层想,任一 \(L > i\) 都会对这次(\(i\))的结果造成影响,所以又可以得到:

\[ans = \sum_{i = 1} ^ {n} P(L \ge 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\) 种放置方案。

所以最终得到一个式子:

\[ans = \sum_{i = 1} ^ {n} \frac{(n - i + 1)A_{n - i}^{k}}{A_{n}^{k + 1}} \]

下面开始爆拆:

\[\begin{aligned} ans &= \sum_{i = 1} ^ {n} \frac{(n - i + 1)A_{n - i}^{k}}{A_{n}^{k + 1}} \\ &= \sum_{i = 1} ^ {n} \frac{(n - i + 1) \times \frac{(n - i)!}{(n - i - k)!}}{\frac{n!}{(n - k - 1)!}} \\ &= \sum_{i = 1} ^ {n} \frac{(n - i + 1)!}{(n - i - k)!} \times \frac{(n - k - 1)!}{n!} \\ &= \frac{(n - k - 1)!}{n!} \times \sum_{i = 1} ^ {n} \frac{(n - i + 1)!}{(n - i - k)!} \\ &= \frac{(n - k - 1)!(k + 1)!}{n!} \times \sum_{i = 1} ^ {n} \frac{(n - i + 1)!}{(n - i - k)!(k + 1)!} \\ &= \frac{(n - k - 1)!(k + 1)!}{n!} \times \sum_{i = 1} ^ {n} C_{n - i + 1}^{k + 1} \\ \end{aligned} \]

到了这里我们发现不好拆了,怎么办?这时我们手中还有一大宝典:组合数的计算。

先把求和函数里面的内容展开得:

\[\sum_{i = 1} ^ {n} C_{n - i + 1}^{k + 1} = C_{n}^{k + 1} + C_{n - 1}^{k + 1} + \cdots + C_{2}^{k + 1} + C_{1}^{k + 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\)。故加上后原式值不变,下面就是愉快的合并:

\[\begin{aligned} \sum_{i = 1} ^ {n} C_{n - i + 1}^{k + 1} &= C_{n}^{k + 1} + C_{n - 1}^{k + 1} + \cdots + C_{2}^{k + 1} + C_{1}^{k + 1} + C_{1}^{k + 2} \\ &= C_{n}^{k + 1} + C_{n - 1}^{k + 1} + \cdots + C_{2}^{k + 1} + C_{2}^{k + 2} \\ &\cdots \\ &= C_{n + 1}^{k + 2} \end{aligned} \]

我们把这个式子带回 开始的式子,会惊奇的发现,我们消掉了一层 \(for\) 循环,而且后面的约分非常爽:

\[\begin{aligned} ans &= \frac{(n - k - 1)!(k + 1)!}{n!} \times \sum_{i = 1} ^ {n} C_{n - i + 1}^{k + 1} \\ &= \frac{(n - k - 1)!(k + 1)!}{n!} \times C_{n + 1}^{k + 2} \\ &= \frac{(n - k - 1)!(k + 1)!}{n!} \times \frac{(n + 1)!}{(n - k - 1)!(k + 2)!} \\ &= \frac{n + 1}{k + 2} \end{aligned} \]

上面实现了对概率的计算,直接求和就行了。其实概率本不能直接求和,但是在某些题目中是可以的(比如这道题和小魔女帕琪)。

至于 \(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;
}
posted @ 2024-08-07 16:26  BLM-dolphin  阅读(15)  评论(0)    收藏  举报