CCF-CSP认证 202012-2 期末预测之最佳阈值

思路写在注释里面了。《算法笔记》P147页,活用递推章节语:“很多题目需要细心考虑过程中是否存在可能的递推关系,如果能找到这样的递推关系,就能使时间复杂度下降不少。例如就一类涉及序列的题目来说,假如序列每一位所需要计算的值都可以通过该位左右两侧的计算结果得到,那么就可以考虑所谓的‘左右两侧的结果’是否能够通过递推进行预处理来得到,这样在后面的使用中就可以不必反复求解。”

PAT B1040/A1093也是这个思路。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
struct Student
{
    int y_{ 0 };
    int result_{ 0 };
};
bool cmp(const Student &lhs, const Student &rhs)
{
    if (lhs.y_ != rhs.y_) return lhs.y_ < rhs.y_;
    return lhs.result_ < rhs.result_;
}
struct ThreeElementArr {
    int y_{ 0 };
    int pass_lower_than_y_{ 0 };
    int fail_higher_than_y_{ 0 };
};
int main()
{
#ifdef LOCAL
    freopen("input.txt", "r", stdin);
#endif
    int m; cin >> m; vector<Student> student_set(m);
    for (int i = 0; i < m; ++i) {
        cin >> student_set[i].y_ >> student_set[i].result_;
    }
    // 根据y,m个人形成一个排序,把m个人划分成rank+1个类(相同的y在相同的类)(rank<m,从0开始)。
    // 维护一个大小为rank+1的数组,数组元素为三元组,
    // 三元组的构成为:{这个rank的y,这个rank之前有多少人过了,这个rank之后有多少人没过};
    // 从前向后扫描一次排好序的student_set获得第二个元,从后向前获得第三个元,时间复杂度O(2N).
    // 再扫描一遍这个数组,第二个元和第三个元加和结果最小的元素的y就是阈值y.
    sort(student_set.begin(), student_set.end(), cmp);
    vector<ThreeElementArr> rank_arr(m);
    // 第二个元,即小于此分数的人中有多少人没过。
    int pass_lower_than_y = 0;
    int rank = 0;
    for (int i = 0; i < m; ++i) {
        if (i == 0) {
            rank_arr[rank].y_ = student_set[i].y_;
        }
        else if (i != 0 && student_set[i].y_ != student_set[i - 1].y_) {
            ++rank;
            rank_arr[rank].y_ = student_set[i].y_;
            rank_arr[rank].pass_lower_than_y_ = pass_lower_than_y;
        }
        if (student_set[i].result_ == 1) {
            ++pass_lower_than_y;
        }
    }
    // 第三个元,也就是分数大于等于此分数的人中有多少人没有过。
    int rrank = rank;
    int fail_higher_tan_y = 0;
    for (int i = m - 1; i >= 0; i--) {
        if (i != m - 1 && student_set[i].y_ != student_set[i + 1].y_) {
            --rrank;
        }
        if (student_set[i].result_ == 0) {
            ++fail_higher_tan_y;
        }
        rank_arr[rrank].fail_higher_than_y_ = fail_higher_tan_y;
    }
    // 寻找和最小的元素的y
    int min=999999999; int min_idx;
    for (int i = rank; i >= 0; --i) {
        if (rank_arr[i].fail_higher_than_y_ + rank_arr[i].pass_lower_than_y_ < min) {
            min = rank_arr[i].fail_higher_than_y_ + rank_arr[i].pass_lower_than_y_;
            min_idx = i;
        }
    }
    cout << rank_arr[min_idx].y_;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值