CodeForces - 732D Exams

期末考试快到了,qdu的考试周一共有n天,你要在这n天里考m门课,这m门课从1到m编号。

我们知道这n天内的每一天可以考哪一门课,当然,也有可能有一天不能考试。 每天只能考一次试。

你每天可以做三件事,考试、复习、或者休息。

每门课都有一个需要复习的天数,比如第i门课需要复习ai天,只有当你总共复习了ai天的第i门课,你才能在考试中通过这第i门课。当然,你也不用非得连续几天都复习一门课,可以穿插着复习,只要最后的天数满足就可以了。

为了尽早回家,你想计算出考完这m门课最少需要多少天?当然每门课都要考通过。要是怎么也不能全部通过,那就输出-1。

还是不太理解题意的话,就去看hint。

Input
第一行两个整数 n 和 m (1 ≤ n, m ≤ 105) — n天,m门课。

第二行n个整数 d1, d2, …, dn (0 ≤ di ≤ m), di 表示这一天可以考第di 门课。如果 di 为 0,那么这一天只能复习或休息,不能考试。

第三行m个整数 a1, a2, …, am (1 ≤ ai ≤ 105), ai 表示通过第i门课至少要复习准备这门课多少天。

Output
输出一个整数。 — 最少多少天可以通过全部的考试。 如果不可能输出-1。

Sample Input
Input1:
7 2
0 1 0 2 1 0 2
2 1

Input2:
10 3
0 0 1 2 3 0 2 0 1 2
1 1 4

Input3:
5 1
1 1 1 1 1
5

Sample Output
Output1:
5

Output2:
9

Output3:
-1
Hint
第一个样例: 第一天和第二天复习科目 1 然后在第五天通过, 第三天复习科目2然后在第四天通过。

第二个样例: 前四天复习科目 3 然后在第五天通过。第六天复习科目 2 然后在第七天通过。第八天复习科目1然后在第九天通过。

第三个样例:时间不够根本通过不了考试。

思路:主要是对最少天数即答案的二分,check函数运用贪心算法,从末位遍历数组,将未考过的入栈,考过的或为0 的作为准备栈顶考试的一天,栈顶元素准备天数大于等于pass的天数即出栈。算法证明:因为将考试尽量往后排就留出了更多的复习时间,所以我们这里是从后往前遍历数组的。

#include<bits/stdc++.h>
using namespace std;
#define maxn 100010
int n,m,i;int top=0;
int day[maxn],p[maxn];
int stack1[maxn];
int visit[maxn];
int pre[maxn];
bool check(int x)
{
    for(i=x;i>0;i--)
    {
        if(pre[stack1[top-1]]>=p[stack1[top-1]]&&top)top--;
        if(!visit[day[i]]&&day[i]){
        stack1[top++]=day[i];
        visit[day[i]]=1;
        }
        else
        {
            pre[stack1[top-1]]++;
        }
    }
    for(i=1;i<=m;i++)
    {
        if(pre[i]<p[i]){return 0;}
    }
    return 1;

}
int main()
{
    cin>>n>>m;
    for(i=1;i<=n;i++){cin>>day[i];}
    for(i=1;i<=m;i++){cin>>p[i];}
    int l=m,r=n+1;
    while(r-l>1)
    {
        top=0;
        memset(visit,0,sizeof(visit));
        for(i=1;i<=m;i++){pre[i]=0;}
        int mid=l+(r-l)/2;
        //while(day[mid]==0)mid--;
        if(check(mid))r=mid;
        else l=mid;
    }
    if(r<=n)cout<<r<<endl;
    else cout<<-1<<endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Shihao Weng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值