CCF CSP认证 202012-2 期末预测之最佳阈值 100分——C++代码

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

题目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


解题思路

看到子任务中有m <= 10^5,看到这里,我们必须条件反射地想到:如果用二重循环暴力求解,则一般会超时!
尝试以后果不其然,仅通过了70%的测试点,拿到70分。

那么,我们究竟如何优化,才能拿到全部的100分呢?

跟几位同学交流后,听到了很多使用一重循环解决的方法,也非常巧妙。下面我就介绍一下我在考场上想到的一种优化二重循环的方法,比较容易看懂。

  • 因为如果用暴力二重循环,会重复很多不必要的遍历和比较操作(遍历阈值时,比如阈值3结束查询,阈值4开始查询,这时比3和4都小的数,以及比3和4都大的数,预测结果是不会变的,但暴力二重循环还是会再全部查询一遍,徒增运行时间!),所以我们有必要进行优化。
  • 首先,用装有pair(就是数对)的容器vector来储存输入数据,同时用集合set存储可选阈值;(set会随着元素的插入自动去重,以及自动排序,非常适合这道题)
  • 输入完成后,将vector按照每个pair的第一个数从小到大排序;
  • 然后,计算当阈值为第一个可选阈值时,预测正确的个数cnt
  • 维护一个用于遍历vector的索引index。这样做的原因:在第一次计算完cnt之后,遍历到剩余的可选阈值时,只需要关注前一个可选阈值与当前遍历到的可选阈值之间的数,计算这些数被预测正确的个数的变化。除此之外的数,要么小于前一个阈值,要么大于等于当前阈值,所以预测结果是不会变的!
  • 随后用for循环遍历剩余可选阈值,每轮都更新cnt,并随时更新max_cnt
  • 因为set中的元素会自动从小到大排好序,所以这样取出的最佳阈值一定满足题目中“多个阈值均可以达到最高准确率时,选取其中最大的”这个条件!

源代码奉上!


C++代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <utility>
#include <set>
#include <algorithm>
using namespace std;

bool cmp(pair<int, int> a, pair<int, int> b)
{
    return a.first < b.first;
}

int main()
{
    int m, y, result;
    scanf("%d", &m);
    vector<pair<int, int> > v(m);
    set<int> theta;
    for (int i = 0; i < m; i++)
    {
        scanf("%d%d", &y, &result);
        v[i] = make_pair(y, result);
        theta.insert(y);
    }
    sort(v.begin(), v.end(), cmp);

    int best = 0, max_cnt = -1, flag, cnt = 0, tmp;
    set<int>::iterator it = theta.begin();
    flag = *it;
    int index = 0;
    for (int i = 0; i < m; i++)
    {
        if (v[i].first < flag)
            tmp = 0;
        else
            tmp = 1;
        if (tmp == v[i].second)
            cnt++;
        if (v[i].first < flag)
            index = i;
    }

    if (cnt >= max_cnt)
    {
        max_cnt = cnt;
        best = flag;
    }

    for (set<int>::iterator it = ++theta.begin(); it != theta.end(); it++)
    {
        flag = *it;
        while (v[index].first < flag) {
            if (v[index].first < flag)
                tmp = 0;
            else
                tmp = 1;
            if (tmp == v[index].second)
                cnt++;
            else
                cnt--;
            index++;
        }
        if (cnt >= max_cnt)
        {
            max_cnt = cnt;
            best = flag;
        }
    }
    printf("%d", best);
    return 0;
}
  • 6
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值