2020年 第21次CCF计算机软件能力认证 202012-2 期末预测之最佳阈值
原题链接:期末预测之最佳阈值
时间限制: 1.0 秒
空间限制: 512 MiB
目录
题目背景
题目描述
输入格式
输出格式
样例1输入
样例1输出
样例1解释
样例2输入
样例2输出
子任务
解题思路
AC代码
期末预测之安全指数
题目背景
考虑到安全指数是一个较大范围内的整数、小菜很可能搞不清楚自己是否真的安全,顿顿决定设置一个阈值 𝜃,以便将安全指数 𝑦转化为一个具体的预测结果——“会挂科”或“不会挂科”。
因为安全指数越高表明小菜同学挂科的可能性越低,所以当 𝑦≥𝜃 时,顿顿会预测小菜这学期很安全、不会挂科;反之若 𝑦<𝜃,顿顿就会劝诫小菜:“你期末要挂科了,勿谓言之不预也。”
那么这个阈值该如何设定呢?顿顿准备从过往中寻找答案。
题目描述
具体来说,顿顿评估了 𝑚位同学上学期的安全指数,其中第 𝑖i(1≤𝑖≤𝑚)位同学的安全指数为 𝑦𝑖,是一个 [0,10^8] 范围内的整数;同时,该同学上学期的挂科情况记作 𝑟𝑒𝑠𝑢𝑙𝑡𝑖∈0,1,其中 0 表示挂科、1 表示未挂科。
相应地,顿顿用 predict𝜃(𝑦)表示根据阈值 𝜃将安全指数 𝑦 转化为的具体预测结果。 如果predict𝜃(𝑦𝑗) 与 𝑟𝑒𝑠𝑢𝑙𝑡𝑗相同,则说明阈值为 𝜃时顿顿对第 𝑗位同学是否挂科预测正确;不同则说明预测错误。
predict𝜃(𝑦) = 0 (𝑦<𝜃)
predictθ(y) = 1 (y≥θ)
最后,顿顿设计了如下公式来计算最佳阈值 𝜃∗ :
𝜃∗=max argmax∑(predict𝜃(𝑦𝑗)==𝑟𝑒𝑠𝑢𝑙𝑡𝑗) 𝜃∈yi j <= 1 <= m
该公式亦可等价地表述为如下规则:
-
最佳阈值仅在 𝑦𝑖 中选取,即与某位同学的安全指数相同;
-
按照该阈值对这 𝑚 位同学上学期的挂科情况进行预测,预测正确的次数最多(即准确率最高);
-
多个阈值均可以达到最高准确率时,选取其中最大的。
输入格式
从标准输入读入数据。
输入的第一行包含一个正整数 𝑚。
接下来输入 𝑚 行,其中第 𝑖i(1≤𝑖≤𝑚)行包括用空格分隔的两个整数 𝑦𝑖和 𝑟𝑒𝑠𝑢𝑙𝑡𝑖,含义如上文所述。
输出格式
输出到标准输出。输出一个整数,表示最佳阈值 𝜃∗。
样例1输入
6
0 0
1 0
1 1
3 1
5 1
7 1
样例1输出
3
样例1解释
按照规则一,最佳阈值的选取范围为{ 0,1,3,5,7}。
𝜃=0 时,预测正确次数为 4;
𝜃=1 时,预测正确次数为 5;
𝜃=3 时,预测正确次数为 5;
𝜃=5 时,预测正确次数为 4;
𝜃=7 时,预测正确次数为 3。
阈值选取为 1 或 3 时,预测准确率最高; 所以按照规则二,最佳阈值的选取范围缩小为 {1,3}。
依规则三,𝜃∗=max(1,3)=3。
样例2输入
8
5 1
5 0
5 0
2 1
3 0
4 0
100000000 1
1 0
样例2输出
100000000
子任务
70%的测试数据保证 𝑚≤200;
全部的测试数据保证 2≤𝑚≤10^5。
解题思路
1.结构体存储数据。
2.要对数据进行排序(从小到大)再处理。
3.找规律(结论):“θ”值为a[i].y时的预测正确次数 = a[i].y前面有多少resullt = 0 + a[i].y当前和后面有多少resullt = 1
4.根据结论,我们需要知道a[i].y前面有多少resullt = 0 以及 a[i].y当前和后面有多少resullt = 1,也就是说要对每个a[i].y前面的result值进行记录,显然用前缀和可求得。
5.求完前缀和后便可计算出“θ”值为a[i].y时的预测正确次数。注意:对于y值相同的数据,我们只处理一次,否则重复进行计算的结果是错误的。
AC代码
#include<bits/stdc++.h>using namespace std;const int N = 1e5 + 10;int m;struct x{int y;int result;int sum0; //记录a[1]——a[i] 有多少resullt = 0int sum1; //记录a[1]——a[i] 有多少resullt = 1int sum; //“θ”值为a[i].y时的预测正确次数 = a[i].y前面有多少resullt = 0 + 当前和后面有多少resullt = 1
}a[N];bool cmp(x a, x b)
{//把y按照从小到大顺序排序 y值相同则把result按从小到大排列if(a.y != b.y) return a.y < b.y;else return a.result < b.result;
}int main()
{cin >> m;for(int i = 1; i <= m; i ++) cin >> a[i].y >> a[i].result;sort(a, a+m+1, cmp); //统计a[1].y 到 a[i].y 的resullt 0 和 1 的数量(实际上就是求前缀和for(int i = 1; i <= m; i ++){if(a[i].result == 1) a[i].sum1 += a[i-1].sum1 + 1, a[i].sum0 = a[i-1].sum0 ;else a[i].sum0 += a[i-1].sum0 + 1, a[i].sum1 = a[i-1].sum1 ;}int ans = 0, max = 0;//统计“θ”值为a[i].y时的预测正确次数for(int i = 1; i <= m; i ++){//注意 遇到y值相同时要特殊处理 即相同的y值只计算一次if(a[i].y == a[i-1].y ) a[i].sum = a[i-1].sum;else a[i].sum = a[i-1].sum0 + a[m].sum1 - a[i-1].sum1 ;if(max <= a[i].sum) max = a[i].sum, ans = a[i].y;}cout << ans << endl;return 0;
}