【贪心算法】Codeforce 1282C Petya and Exam

继续撸题!撸一道然后去搞SLAM.

一、题目大意

题目的大致意思是,Petya要参加一场考试,试卷一共n道题,分两种题目,一种是Easy,一种是Hard,对于Easy类题目,Petya需要花费a分钟解决,Hard类题目需要花费b分钟解决,考试一共T分钟。在考试途中,Petya可以随时离开,暂时记离开时间为T1,同时每道题目有一个限定时间,如果T1超过这个限定时间,而且对应的题还没有做出来的话,直接记0分,否则按Petya离开时已经做的题目数量计分。

要求求解Petya在这场考试中最多可以拿到多少分?

二、题目思路以及AC代码

这题的题目思路个人感觉不太好想,但好在样例给的数据涵盖的情况比较全面(可能是过年要发的福利吧)

题目思路大致如下,我们可以考虑Petya不同的离开时间,这里我觉得用一个例子比较好说明。

输入数据:

6 20 2 5
1 1 0 1 0 0
0 8 2 9 11 6

对于这组输入数据,我们肯定想要先把限定时间靠前的一部分工作先做,首先将其按照限定时间从小到大的顺序进行排序(注意要把题目种类一起排序)。

排序之后,我们考虑Petya离开的时间,其实只要不涉及到限定时间,那么我们只需要把简单的题先做,然后做难的题,所得到的答案肯定最大。但是这里要求了限定时间,我们就只需用限定时间区分Petya离开的不同时间即可,是什么意思呢?看我下面的算法步骤。

首先排序之后

5 2 2 5 5 2
0 2 6 8 9 11

这里第一行我直接用了题目花费时间。cur_T表示当前时间,初始为0.

然后我们最初的考虑,直接按这个顺序取就可以了嘛(虽然后来证明并不对),先考虑能不能一道题不做就出去,发现不行,因为第一个的限定时间是0,所以做第一个,cur_T = 5,然后考虑可不可以做完第一题就出去,发现不可以,因为cur_T大于第二个的限定时间,所以必须做第二个,然后再考虑可不可以做完第三题出去,同样cur_T = 7 > 6,也不可以,…,最后发现都不可以,结果是0.

我们发现,我们只需要比较上一个做完的时间,和下一个的限定时间,就决定了我们能不能在上一个题做完之后离开,然后我们需要做的,就是在这些离开的时间点求所能得得最多得分数,再取最大即可。

但这里还有一个问题,不要简单的以为从哪里出去,分数就是前面的几个,我将上面的数据修改一下你就明白了。

5 1 1 5 5 1
0 8 8 8 9 11

这样的话,当我判断可以在做完第一题后就离开,那么我这时离开的最大分数就是1吗?并不是,你会发现,你可以顺便把后面的简单题都做了,因为它并不影响你离开,正确的答案应该是3,第一题再加上之后的两个简单题。

上述就是整道题的思路,个人觉得讲的还是比较清楚的,下面给出AC代码。

AC代码:

/*
 * Codeforce 1282C:
 * @ Author:    Johnson
 * @ Date:      2019.12.29
 */ 
#include <iostream>
#include <algorithm>
#include <vector>
#define MAXN 200010
using namespace std;

struct Problem {
    bool type;          // false: 简单题    true: 难题
    int end_time;       // 截至时间
    int cost_time;
};

Problem problems[MAXN];

bool cmp(Problem a, Problem b) {
    if (a.end_time != b.end_time) return a.end_time < b.end_time;
    else return a.cost_time < b.cost_time;
}

int main() {

    int m;
    cin >> m;

    while(m--) {
        int n, T, a, b;
        cin >> n >> T >> a >> b;

        int num_a = 0;
        for (int i=1;i<=n;i++) {
            cin >> problems[i].type;
            if (problems[i].type) problems[i].cost_time = b;
            else {
                problems[i].cost_time = a;
                num_a++;
            }
        }

        for (int i=1;i<=n;i++) {
            cin >> problems[i].end_time;
        }

        // 按照end_time从小到大排序
        sort(problems+1, problems+n+1, cmp);
        problems[n+1].end_time = T + 1;

        long long cur_T = 0;
        int score = 0;
        for (int i=0;i<=n;i++) {
            if (!problems[i+1].type && num_a > 0) num_a--;
            if (cur_T < problems[i+1].end_time) {
                int diff = problems[i+1].end_time - cur_T - 1;
                score = max(score, i + min(static_cast<int>(diff / a), num_a));
            }
            cur_T += problems[i+1].cost_time;
        }

        cout << score << endl;
    }

    return 0;
}

如果有问题,欢迎大家指正!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值