Exams(二分求左界+贪心)

来源:互联网 发布:最火的网络用语 编辑:程序博客网 时间:2024/06/06 12:53
用力戳我直达原题:D - Exams

题意:

有N天和M门课程。

接下来给你N天的行为,0表示这一天只能预习,[1,m]表示这一天可以考这门课(当然这一天你也可以选择不考或者预习)。

接下来给你M个数cost[i],代表第i门课需要预习cost[i]天才能PASS。

求从第一天起算,最少需要几天才能PASS所有功课,如果N天都PASS不了,则输出-1。

做法:

1.先判断用N天能否PASS,不能就输出-1。

2.low = m, high = n。求左界。

3-1 judge的时候,一门课肯定越慢考越容易通过,所以从mid开始找,第一次遇到的功课标记vis[day[i]]。

3-2 如果day[i]等于0或者day[i]已经访问过了,也就是说这一天能用来复习,sum++;

3-3 如果sum >= 预习所需要的总时间sum_cost,且所有课程都有安排考试,说明时间充裕,返回true。

3-4 第一天肯定只能拿来复习不能拿来考试,所以sum初始化为1,遍历从 mid -> 2

3-5从mid开始找到第一个不是0的数,因为这些天的复习是无效的,后面无考试了。


#include <bits/stdc++.h>using namespace std;int day[100100];int sum_cost = 0;bool vis[100100];int n, m, x;bool judge(int mid) {    memset(vis, false, sizeof(vis));    while(day[mid] == 0) mid--;    int sum = 1;  //累加预习时间    int tot = 0;  //累加安排考试科目数    for(int i = mid; i >= 2; i--) {        int cur = day[i];        if(vis[cur] || cur == 0) sum++;        else tot++, vis[cur] = true;    }    return (sum >= sum_cost && tot == m);}int main() {    scanf("%d%d", &n, &m);    for(int i = 1; i <= n; i++) scanf("%d", day+i);    for(int i = 1; i <= m; i++) scanf("%d", &x), sum_cost += x;  //累计最终需要多少天    if(judge(n) == false) {        puts("-1");        return 0;    }    int low = m, high = n;    while(low < high) {        int mid = low + high >> 1;        if(judge(mid)) high = mid;        else low = mid + 1;    }    printf("%d\n", high);}


原创粉丝点击