寒训1G Exams

文章介绍了一个关于如何在有限时间内完成所有课程测验的问题。通过顺序遍历考试,计算前缀和,并尝试调整考试顺序,以确定是否可能在规定天数内完成所有复习和测验。如果不能完成,则输出-1。最后,给出了一段C++代码实现该算法。
摘要由CSDN通过智能技术生成

题意

Vasiliy需要在接下来的天内进行门功课的测验,对于第i门功课他需要天来复习和一天来考试,并且他知道在这天内每天可以进行哪一门功课的测验(或者没得考试)。在这天内每一天他可以选择进行某门功课的测验,或者选择复习某门功课(只能选一个!)现在你要帮他算一下他能否在这天内通过所有功课的测验,如果能的话输出通过所有测验的最小天数,否则输出

思路

首先考试肯定是能考就考,要考就要先复习!从第一门考试开始看起......秉持着能考就考的原则,第一门考试当然要考!第二门也要!第三门!......可以发现,如果我们要进行某几门测验,就要花费这几门测验所需的(复习+考试(一天))时间之和,而我们拥有的时间刚好就是这几门测验里最后一门测验的时间——时间之和,顺序遍历考试——前缀和!于是思路骤然明朗:

顺序遍历一遍所有考试,处理一下考试所需时间的前缀和,并与这几门测验里的最后一门测验的时间点进行比较,若考试时间大于测验时间则说明不行,反之则可以。

但是我们需要考完所有考试吗?首先已经通过的功课不需要再去考了,因此在进行考试之前要先掂量一下是否已经进行测验(用一个布尔数组来记录)接着,一门功课并不只有一个时间点,在发现考不了的时候可以将某门功课向后面拖一下来“借”点时间嘛——如果借不了答案也就出来了:不行。

对于最小值,只需要直接用最后一场考试的时间点覆盖即可(因为如果考试结束,后面的考试直接跳过,是不会覆盖答案的)最后思路总结:

顺序遍历一遍所有考试,处理一下应考考试所需时间前缀和,并与这几门考试里的最后一门的时间点进行比较,若考试时间大于测验时间则尝试将某门已考测验后延(包括本场考试。若找不到则证明无法完成所有测验,停止遍历并直接输出结果)

遍历结束后若全部考完(当心有功课没得考!)输出最后一门应考考试结束的时间点。

代码

#include <iostream>
using namespace std;
int n, m, p;
int day[100005], sub[100005];
int ans;                                        //答案
bool accepted[100005];

struct exam {
    int day, sub;
} ex[100005];

int main() {

    cin >> n >> m;
    for (int i = 1; i <= n; ++i)
        cin >> day[i];
    for (int i = 1; i <= m; ++i) {
        cin >> sub[i];
        sub[i] ++;
    }
    for (int i = 1; i <= n; ++i) {
        if (day[i] == 0)
            continue;
        ex[++p] = {i, day[i]};
    }
    //处理为p个考试下的问题,利用前缀和得到准备时间(附带考试时间)
    int sum = 0;    //不考试的话准备时间就是0了
    for (int i = 1; i <= p; ++i) {
        if (accepted[ex[i].sub])
            continue;        //考完了就不用管了
        sum += sub[ex[i].sub];
        accepted[ex[i].sub] = true;
        ans = ex[i].day;
        while (sum > ex[i].day) {                    //时间不够?这下得专心复习这一科了
            if (i >= p) {
                cout << -1;        //挤不出时间?寄
                return 0;
            }
            for (int j = i + 1; j <= p; ++j) {
                if (accepted[ex[j].sub]) {
                    sum -= sub[ex[j].sub];
                    accepted[ex[j].sub] = false;
                    break;
                }
                if (j >= p) {
                    cout << -1;        //挤不出时间?寄
                    return 0;
                }
            }
        }
    }
    for (int i = 1; i <= m; ++i) {
        if (!accepted[i]) {
            cout << -1;
            return 0;
        }
    }
    cout << ans;
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值