CCF期末预测之最 佳阈值

本文探讨了一种高效算法,通过前缀后缀计数法寻找在给定序列中,预测学生考试结果的最佳阈值,以达到最高正确率。两种C++实现方式对比,暴力求解与巧妙优化的效率和复杂度分析。

最佳居然发不出来

题目背景

在这里插入图片描述

题目描述

在这里插入图片描述

输入格式

在这里插入图片描述

输出格式

在这里插入图片描述

样例

输入

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

输出

3

C++解答

我自己想的当然还是暴力求解,把所有y都当成阈值遍历一遍,找到最大正确率的阈值,不知道为啥只得了50分

#include<iostream>
using namespace std;
int main()
{
    int n;
    int a=0;
    int max_num=0,max_a=0;
    cin>>n;
    int y[n];
    int result[n];
    for(int i=0;i<n;i++){
        cin>>y[i]>>result[i];
    }
    for(int i=0;i<n;i++){
        a=y[i];
        int num=0;
        for(int j=0;j<n;j++){
            int result_predict;
            if(y[j]<a) result_predict=0;
            else result_predict=1;
            if(result_predict==result[j]) num++;
        }
        if(num>=max_num) {
            max_num=num;
            max_a=a;
        }
    }
    cout<<max_a;
    return 0;
}

发现了一个前缀后缀的巧妙方法
先把阈值进行排序,通过计算每个值在序列中前面为0,后面为1的个数(真实),对于一个阈值来说自己预测的肯定是前面都为0后面都为1,因此真实的个数和最多的就是最佳阈值

#include<iostream>
#include<algorithm>
using namespace std;
pair<int,int> pii[100005];      //pair数组储存信息,每个pair存储一个同学的y和result
int pre0[100005];               //记录该位置及前面的result为0的个数(前缀和)
int rear1[100005];              //记录该位置及后面的result为1的个数(后缀和)
int k = -1,ma = 0;              //k用来记录最佳阈值,ma用来存储最佳阈值对应的预测成国公数目
int main(){
    int m;
    cin>>m;                     //输入m
    pii[0] = pair<int,int>(-1,-1);
    for(int i = 1;i <= m;++i)   //初始化pii数组
        cin>>pii[i].first>>pii[i].second;
    sort(pii + 1,pii + 1 + m);  //将所有学生信息按照阈值从小到大排序,方便后续前缀后缀和的操作
    for(int i = 1;i <= m;++i)            //记录前缀0个数
        if(pii[i].second == 0)
            pre0[i] = pre0[i - 1] + 1;
        else
            pre0[i] = pre0[i - 1];
    for(int i = m;i >= 1;--i)           //记录后缀1个数
        if(pii[i].second == 1)
            rear1[i] = rear1[i + 1] + 1;
        else
            rear1[i] = rear1[i + 1];
    for(int i = 1;i <= m;++i){          //最终处理
        if(pii[i].first == pii[i - 1].first)
            continue;                   //如果有阈值相同的情况,那么在相同区间的第一个位置统计了,直接跳过
        if(ma <= pre0[i - 1] + rear1[i])//更新k和ma
            ma = pre0[i - 1] + rear1[i],k = pii[i].first;
    }
    cout<<k;
    return 0;
}

2020年12月CCF期末预测相关涉及两个方面,一是期末预测最佳阈值,二是期末预测之安全指数。 期末预测最佳阈值问题中,最佳阈值仅在 𝑦𝑖 中选取,即与某位同学的安全指数相同;按照该阈值对这 𝑚 位同学上学期的挂科情况进行预测预测正确的次数多(即准确率高);多个阈值均可以达到高准确率时,选取其中大的。在解决该问题时,存在超时问题,可改用快排 + for,此时时间复杂度变为由快排决定的 nlogn。通过两个单独的 for 循环别计算前后成功的情况数值,再进行比较。也可在计算之前先将结构体数组按 y 递增排序,这样能从小到大选取阈值,并且方便统计以 y 为界的左右两边的情况。还可以使用 map<int, pair<int, int> > y2result 来存储不同安全指数的未通过和通过的人数,进而计算预测正确的人数 [^1][^2][^3][^4]。 以下是修改后的代码示例: ```cpp #include<bits/stdc++.h> using namespace std; struct node { //结构体 int x,y,z; }; bool cmp(const node &a,const node &b) { //按着x的升序和y的降序排列 if(a.x !=b.x ) return a.x<b.x ; return a.y>b.y; } int main() { int n;//数据输入 cin>>n; node A[n]; for(int i=0; i<n; i++) cin>>A[i].x>>A[i].y; sort(A,A+n,cmp);//排序 int sum=0; for(int i=0; i<n; i++) { //以自身为判断标准,记录自身前面的预测成功情况 A[i].z=sum;//第一个为0 if(A[i].y==0) sum++; } sum=0; //以自身为判断标准,记录自身以及自身后面的预测成功情况 for(int i=n-1; i>=0; i--) { if(A[i].y==1) sum++; A[i].z+=sum;//如果自己是1,那么加上这种成功的情况 } //比较预测正确的次数 int tmp=A[0].z; int k=0; for(int i=0;i<n;i++){ if(tmp<=A[i].z){//比较更新值 tmp=A[i].z; k=A[i].x;//记录更新值 } } cout<<k<<endl;//输出 } ``` 期末预测之安全指数问题是送题,理解题目后计算乘积之和即可 [^5]。 以下是其代码示例: ```cpp #include<stdio.h> #include<algorithm> #include<queue> #include<stack> using namespace std; const int maxn=1e5+5; typedef long long LL; int s1[maxn]; int n; int main() { scanf("%d",&n); int a,b; int sum=0; for(int i=1; i<=n; i++) { scanf("%d%d",&a,&b); sum+=a*b; } if(sum<=0) printf("0\n"); else printf("%d",sum); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值