CCF-CSP 202012-2 期末预测之最佳阈值 (Python)

题目背景

考虑到安全指数是一个较大范围内的整数、小菜很可能搞不清楚自己是否真的安全,顿顿决定设置一个阈值 θ \theta θ,以便将安全指数 y y y 转化为一个具体的预测结果——“会挂科”或“不会挂科”。
因为安全指数越高表明小菜同学挂科的可能性越低,所以当 y ≥ θ y \ge \theta yθ 时,顿顿会预测小菜这学期很安全、不会挂科;反之若 y < θ y \lt \theta y<θ,顿顿就会劝诫小菜:“你期末要挂科了,勿谓言之不预也。”
那么这个阈值该如何设定呢?顿顿准备从过往中寻找答案。

题目描述

具体来说,顿顿评估了 m m m 位同学上学期的安全指数,其中第 i i i 1 ≤ i ≤ m 1 \le i \le m 1im)位同学的安全指数为 y i y_i yi,是一个 [ 0 , 1 0 8 ] [ 0, 10^8 ] [0,108] 范围内的整数;同时,该同学上学期的挂科情况记作 r e s u l t i ∈ 0 , 1 result_i \in { 0, 1 } resulti0,1,其中 0 0 0 表示挂科、 1 1 1 表示未挂科。
相应地,顿顿用 p r e d i c t θ ( y ) predict_{\theta} ( y ) predictθ(y) 表示根据阈值 θ \theta θ 将安全指数 y y y 转化为的具体预测结果。
如果 p r e d i c t θ ( y j ) predict_{\theta} ( y_j ) predictθ(yj) r e s u l t j result_j resultj 相同,则说明阈值为 θ \theta θ 时顿顿对第 j j j 位同学是否挂科预测正确;不同则说明预测错误。
在这里插入图片描述
最后,顿顿设计了如下公式来计算最佳阈值 θ ∗ \theta^* θ
在这里插入图片描述
该公式亦可等价地表述为如下规则:

  1. 最佳阈值仅在 y i { y_i } yi 中选取,即与某位同学的安全指数相同;
  2. 按照该阈值对这 m m m 位同学上学期的挂科情况进行预测,预测正确的次数最多(即准确率最高);
  3. 多个阈值均可以达到最高准确率时,选取其中最大的。

输入格式

从标准输入读入数据。
输入的第一行包含一个正整数 m m m
接下来输入 m m m 行,其中第 i i i 1 ≤ i ≤ m 1 \le i \le m 1im)行包括用空格分隔的两个整数 y i y_i yi r e s u l t i result_i resulti,含义如上文所述。

输出格式

输出到标准输出。
输出一个整数,表示最佳阈值 θ ∗ \theta^* θ

样例1输入

6
0 0
1 0
1 1
3 1
5 1
7 1

样例1输出

3

样例1解释

按照规则一,最佳阈值的选取范围为 0 , 1 , 3 , 5 , 7 { 0, 1, 3, 5, 7 } 0,1,3,5,7
θ = 0 \theta = 0 θ=0 时,预测正确次数为 4 4 4
θ = 1 \theta = 1 θ=1 时,预测正确次数为 5 5 5
θ = 3 \theta = 3 θ=3 时,预测正确次数为 5 5 5
θ = 5 \theta = 5 θ=5 时,预测正确次数为 4 4 4
θ = 7 \theta = 7 θ=7 时,预测正确次数为 3 3 3
阈值选取为 1 1 1 3 3 3 时,预测准确率最高;
所以按照规则二,最佳阈值的选取范围缩小为 1 , 3 { 1, 3 } 1,3
依规则三, θ ∗ = max ⁡ 1 , 3 = 3 \theta^* = \max { 1, 3 } = 3 θ=max1,3=3

样例2输入

8
5 1
5 0
5 0
2 1
3 0
4 0
100000000 1
1 0

样例2输出

100000000

子任务

70 % 70\% 70% 的测试数据保证 m ≤ 200 m \le 200 m200
全部的测试数据保证 2 ≤ m ≤ 1 0 5 2 \le m \le 10^{5} 2m105

解法

若暴力使用两层for循环会超时,只能拿70分,这里采用前缀和的思想。

m = int(input())
yr = []
# 全部挂科情况的和
sum_r = 0
for i in range(m):
    y, r = list(map(int, input().split()))
    yr.append([y, r])
    sum_r += r
yr = sorted(yr)     # 按安全指数进行从小到大排序
# 存储当前安全指数前面不挂科的和(即对当前安全指数前面的挂科情况求和)
sum = [0]
# 最高准确率
max_acc = sum_r
# 最佳阈值
optimum_yuzhi = yr[0][0]
# 上一个阈值
last_yuzhi = yr[0][0]
for idx, [y, r] in enumerate(yr):
    if idx == 0:
        continue
    sum.append(yr[idx - 1][1] + sum[idx - 1])
    # 当阈值不一样才会去计算当前阈值的准确率
    if y > last_yuzhi:
        last_yuzhi = y
        acc = (idx - sum[idx]) + (sum_r - sum[idx]) # 阈值前0的个数 + 阈值后(包括该阈值)1的个数
        if acc >= max_acc:
            optimum_yuzhi = y
            max_acc = acc
print(optimum_yuzhi)

你可能感兴趣的:(CCF-CSP,python,算法,经验分享)