CFcontest377-D 贪心,二分

昨天从银川坐车回学校,下午冲过来做题也就过了一题,今天算是正式回归,感觉眼睛和手都生疏了。读英文题的速度本来就是弱项,越发地读不明白了。
今天战绩3/6,排名倒倒数,下午会了一道题,感觉收获颇深。

题目的大致意思就是一个人要去考试,每天只能考一科或者复习或者休息,然后一共有m科要考试,n天准备+考试,每科只能在特定的时间考试。对一个科目的考试时间不需要连续。
输入n,m,接下来两行分别输入两个数组,第一个是每天可以考试的安排,第二个是每一科目需要的复习时间。
我拿到这个题之后想到的是动态规划,因为我从来没有用动态规划成功地解出过题,所以就放弃了,后来证明我真的是做题太少了,对很多题目没有基本的把握。

题目有两个关键,①每一科复习的时间不需要具体规定,只要天数够即可。②先考哪一个不是重点,关键是每一科最后考的是哪一个。那么就来看每一天这个元素,如果是0,那么可以用来复习,如果是某一考试时间,如果考试已经定了在哪一天,这一天即与0无异,可是算作复习的天数。

题目还要求是最少的天数,我对最少有一个误解,就是最少必须一下子求出来,其实不是,本题就巧妙地先将眼光投在整个数组,从后往前扫,关键就在于那个“结束”的位置,寻找那个结束的位置在哪里,其实类似寻找符合条件的最大的在哪里,然后就可以用到二分法,二分最关键的是缩小范围,这个题也是在不断缩小终点的范围找到那个符合条件的最小的。

题目收获:
①从后往前扫,关键
②二分的扩展应用

PS:每次看到一个复杂的程序,其中的逻辑关系精巧得让我钦佩的时候,就会想:这都能写对,错一点点不就全盘皆输了嘛。
自己敲的时候会觉得,这是一个思维的展现的过程,自己想出来的正确的东西,总会写对(哈哈,让我展望一下自己的未来)。

代码:

#include<iostream>
using namespace std;
#include<algorithm>

const int Maxn = 100005;
int n, m;
int day[Maxn], need[Maxn], vis[Maxn];

bool judge(int x)//x就是那个终点
{
    memset(vis, 0, sizeof(vis));
    int sum = 0, count = 0;
    //sum记录的是复习需要的时间,然后在可以复习的时候就会相应减少,count记录的是选择了要考试的科目
    int i;
    for (i = x; i >= 1; i--)
    {
        if (day[i])
        {
            if (!vis[day[i]])
            {
                sum += need[day[i]];
                count++;
                vis[day[i]] = 1;
            }
            else
                if (sum != 0)
                    sum--;
        }
        else
            if (sum != 0)
                sum--;
    }
    if (sum != 0 || count != m)
        return false;
    else
        return true;
}

void binary(int l, int r)
{
    while (l < r)
    {
        int min = (l + r) / 2;//二分的关键
        if (judge(min))//二分的关关键
            r = min;
        else
            l = min + 1;
    }
    if (judge(l))
        cout << l << endl;
    else
        if (judge(r))
            cout << r << endl;
        else
            cout << "-1" << endl;
}
int main()
{
    while (cin >> n >> m)
    {
        int i;

        for (i = 1; i <= n; i++)
            cin >> day[i];
        for (i = 1; i <= m; i++)
            cin >> need[i];
        binary(1, n);
    }
    return 0;
}

又敲了一遍代码,感觉ACM中vis是个很重要的东西很多题目从后往前遍历可能柳暗花明不要把题目想得太复杂,我算不明白的题计算机说不定会呢。

附题目:

D. Exams

time limit per test:1 second

memory limit per test:256 megabytes

input:standard input

output:standard output

Vasiliy has an exam period which will continue for n days. He has to pass exams on m subjects. Subjects are numbered from 1 to m.

About every day we know exam for which one of m subjects can be passed on that day. Perhaps, some day you can’t pass any exam. It is not allowed to pass more than one exam on any day.

On each day Vasiliy can either pass the exam of that day (it takes the whole day) or prepare all day for some exam or have a rest.

About each subject Vasiliy know a number ai — the number of days he should prepare to pass the exam number i. Vasiliy can switch subjects while preparing for exams, it is not necessary to prepare continuously during ai days for the exam number i. He can mix the order of preparation for exams in any way.

Your task is to determine the minimum number of days in which Vasiliy can pass all exams, or determine that it is impossible. Each exam should be passed exactly one time.

Input

The first line contains two integers n and m (1 ≤ n, m ≤ 105) — the number of days in the exam period and the number of subjects.

The second line contains n integers d1, d2, …, dn (0 ≤ di ≤ m), where di is the number of subject, the exam of which can be passed on the day number i. If di equals 0, it is not allowed to pass any exams on the day number i.

The third line contains m positive integers a1, a2, …, am (1 ≤ ai ≤ 105), where ai is the number of days that are needed to prepare before passing the exam on the subject i.

Output

Print one integer — the minimum number of days in which Vasiliy can pass all exams. If it is impossible, print -1.

Examples

Input
7 2
0 1 0 2 1 0 2
2 1

Output
5

Input
10 3
0 0 1 2 3 0 2 0 1 2
1 1 4

Output
9

Input
5 1
1 1 1 1 1
5

Output
-1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值