参考文章
https://blog.csdn.net/SUN__CGJ/article/details/111224076
题目描述
具体来说,顿顿评估了 𝑚 位同学上学期的安全指数,其中第 𝑖(1≤𝑖≤𝑚)位同学的安全指数为 𝑦𝑖,是一个 [0,108] 范围内的整数;同时,该同学上学期的挂科情况记作 𝑟𝑒𝑠𝑢𝑙𝑡𝑖∈0,1,其中 0 表示挂科、1 表示未挂科。
相应地,顿顿用 𝑝𝑟𝑒𝑑𝑖𝑐𝑡𝜃(𝑦) 表示根据阈值 𝜃 将安全指数 𝑦 转化为的具体预测结果。 如果 𝑝𝑟𝑒𝑑𝑖𝑐𝑡𝜃(𝑦𝑗) 与 𝑟𝑒𝑠𝑢𝑙𝑡𝑗 相同,则说明阈值为 𝜃 时顿顿对第 𝑗 位同学是否挂科预测正确;不同则说明预测错误。
最后,顿顿设计了如下公式来计算最佳阈值 𝜃∗
该公式亦可等价地表述为如下规则:
最佳阈值仅在 𝑦𝑖 中选取,即与某位同学的安全指数相同;
按照该阈值对这 𝑚 位同学上学期的挂科情况进行预测,预测正确的次数最多(即准确率最高);
多个阈值均可以达到最高准确率时,选取其中最大的。
输入格式
从标准输入读入数据。
输入的第一行包含一个正整数 𝑚。
接下来输入 𝑚 行,其中第 𝑖(1≤𝑖≤𝑚)行包括用空格分隔的两个整数 𝑦𝑖 和 𝑟𝑒𝑠𝑢𝑙𝑡𝑖,含义如上文所述。
输出格式
输出到标准输出。
输出一个整数,表示最佳阈值 𝜃∗。
样例1输入
6
0 0
1 0
1 1
3 1
5 1
7 1
样例1输出
3
1
样例2输入
8
5 1
5 0
5 0
2 1
3 0
4 0
100000000 1
1 0
样例2输出
100000000
题解
- 首先看到n为1e5,两层循环肯定是超时的,只能得70分!
- 本题正解思路是,对所有输入进行排序,记录比自己小的标签其值且0的个数,比自己大标签且其值的1的个数。实际上是用排序的方式,减少了重复多余的比较(nlogn)
代码实现
#include<iostream>
#include<algorithm>
using namespace std;
int n;
const int MAX = 2e5+5;
struct node{
int x,y;
}a[MAX];
struct node2{
int x,l,u,sum;
}tag[MAX];
bool cmp1(node t1,node t2){
return t1.x<t2.x;
}
bool cmp2(node2 t1,node2 t2){
if(t1.sum==t2.sum){
return t1.x<t2.x;
}
return t1.sum<t2.sum;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].y;
}
sort(a+1,a+n+1,cmp1); // 按照第一个数(标签)升序排序
int k=1;
tag[k].x = a[1].x; // 设置第1个标签
for(int i=1;i<=n;i++){
if(tag[k].x==a[i].x){ // 该标签已设置
if(a[i].y==1) tag[k].u++; // 该标签为1计数+1
else tag[k].l++; // 该标签为0计数+1
}
else{ // 该标签未设置
tag[++k].x = a[i].x;
if(a[i].y==1) tag[k].u++; // 该标签为1计数+1
else tag[k].l++; // 该标签为0计数+1
}
}
int sum=0;
// 计算该标签下(包含该标签)有多少个0
for(int i=1;i<=k;i++){
sum += tag[i].l;
tag[i].l = sum;
}
sum = 0;
// 计算该标签下(包含该标签)有多少个1(即求多少个大于等于该标签的数)
for(int i=k;i>=1;i--){ // 注意1是从大的往小的方向累积
sum += tag[i].u;
tag[i].u = sum;
}
// 每个的次数=比自己标签小且其值为0的个数+大于等于自己的标签且其值为1的个数
for(int i=1;i<=k;i++){
tag[i].sum = tag[i].u+tag[i-1].l;
}
sort(tag+1,tag+k+1,cmp2);
cout<<tag[k].x<<endl;
return 0;
}