题目链接
题目描述
一份试卷有 道单项选择题,第
题有
个选项。每道题的正确答案都是从其选项中等概率随机选出的。
旺仔哥哥本来做对了所有题目,但在誊写答案时,发生了错位:
- 原第
题的答案被写到了第
题的位置 (对于
)。
- 原第
题的答案被写到了第
题的位置。
求在这种情况下,旺仔哥哥期望能答对多少题。
输入:
- 第一行一个整数
,表示题目数量。
- 第二行
个整数
,表示每道题的选项数。
输出:
- 输出一个实数,表示期望答对的题目数。
解题思路
本题的核心是利用期望的线性性质。
1. 期望的线性性质
- 设
为总共答对的题目数,这是一个随机变量。我们要求的是
。
- 根据期望的线性性质,
等于每道题答对的期望之和。
- 我们可以为每道题定义一个指示器随机变量
:
- 那么,总答对数
。
- 根据期望的线性性质,
。
- 对于一个指示器随机变量,
等于它取值为
的概率,即第
题答对的概率
。
- 所以,最终的期望答对题目数就是所有题目各自答对的概率之和:
。
2. 计算每道题答对的概率
现在问题转化为计算每一道题答对的概率。
-
对于第 1 题:
- 写到第 1 题位置上的答案,实际上是原来第
题的正确答案。
- 这个答案是第
题
个选项中的一个。
- 而第 1 题的正确答案,是独立地从它自己的
个选项中随机选出的。
- 这两个答案恰好相等的概率是
。
- 解释:假设
。第
题的答案有
种可能。第 1 题的答案要与它相同,只有
的概率。同时,这两个答案必须都存在于较小的选项集合中。因为第
题的答案是从
中选,第 1 题的正确答案是从
中选。如果第
题的答案大于
,那么第 1 题永远不可能答对。所以,第
题的答案必须落在
范围内(概率为
),并且第 1 题的正确答案恰好是这个数(概率为
)。总概率是
。对称地,当
时,概率为
。
- 解释:假设
- 写到第 1 题位置上的答案,实际上是原来第
-
对于第
题 (其中
):
- 写到第
题位置上的答案,是原来第
题的正确答案。
- 这个答案是第
题
个选项中的一个。
- 第
题的正确答案是从它自己的
个选项中独立随机选出的。
- 同理,这两个答案相等的概率是
。
- 写到第
3. 汇总计算
- 将所有概率相加即可得到最终的期望值:
算法很简单:
- 读取
和数组
。
- 计算第 1 题的答对概率
。
- 循环从
到
,累加第
题的答对概率
。
- 输出总和。
代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <iomanip>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
double expected_value = 0.0;
// 计算第 1 题的期望
if (n > 0) {
expected_value += 1.0 / max(a[0], a[n - 1]);
}
// 计算第 2 到 n 题的期望
for (int i = 1; i < n; i++) {
expected_value += 1.0 / max(a[i], a[i - 1]);
}
cout << fixed << setprecision(15) << expected_value << endl;
return 0;
}
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; i++) {
a[i] = sc.nextInt();
}
double expectedValue = 0.0;
// 计算第 1 题的期望
if (n > 0) {
expectedValue += 1.0 / Math.max(a[0], a[n - 1]);
}
// 计算第 2 到 n 题的期望
for (int i = 1; i < n; i++) {
expectedValue += 1.0 / Math.max(a[i], a[i - 1]);
}
System.out.printf("%.15f\n", expectedValue);
}
}
import sys
def main():
n = int(sys.stdin.readline())
if n == 0:
print(0.0)
return
a = list(map(int, sys.stdin.readline().split()))
expected_value = 0.0
# 计算第 1 题的期望
expected_value += 1.0 / max(a[0], a[n - 1])
# 计算第 2 到 n 题的期望
for i in range(1, n):
expected_value += 1.0 / max(a[i], a[i - 1])
print(f"{expected_value:.15f}")
if __name__ == "__main__":
main()
算法及复杂度
- 算法:数学期望 + 概率计算
- 时间复杂度:只需要遍历一次输入的数组来累加概率,因此时间复杂度为
。
- 空间复杂度:需要一个数组来存储每道题的选项数,空间复杂度为
。