Exams 二分法

来源:互联网 发布:js eval 编辑:程序博客网 时间:2024/05/22 01:46

题目来源:Codeforces Round #377 (Div. 2)

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

Note

In the first example Vasiliy can behave as follows. On the first and the second day he can prepare for the exam number 1 and pass it on the fifth day, prepare for the exam number 2 on the third day and pass it on the fourth day.

In the second example Vasiliy should prepare for the exam number 3 during the first four days and pass it on the fifth day. Then on the sixth day he should prepare for the exam number 2 and then pass it on the seventh day. After that he needs to prepare for the exam number 1 on the eighth day and pass it on the ninth day.

In the third example Vasiliy can’t pass the only exam because he hasn’t anough time to prepare for it.

题目大意:
第一行输入两个数,第一个数为考试天数n,第二个数为考试科目m
第二行输入n个数,表示每一天的考试状态:d[i]表示第i天可以过第d[i]个科目,d[i]==0时表示今天不可以考试,只能复习或者休息
第三行输入m个数,表示每个科目分别需要复习多少天。只有在d[i]==0的时候或者不考试的时候复习
求最短的日子完成考试是第几天

做题思路:
用二分法
二分法就是拦腰折断判断所求的数在二分之一之前还是之后,调整起始点或结束点,重新划分判断范围。
当起点大于等于终点的时候跳出循环,此时判断起点是否满足能够复习完每一科目,如果可以即可输出,否则输出-1。

误区与问题解释:
最开始的想法是正着找,即贪心,发现可能会有不够最优的情况出现,比如有的考试即使可以过但是为了大局也需要放弃。
于是就想着要反着找,却没有想到怎么能够当出现了更好的选择的时候改变已经做好的东西,简单地说就是能保证答案可行,但不能保证答案最优。
二分法虽然要判断很多次,但是这个思路不是按照天数来推理,而是当这一天作为结束的时候是否可以完成考试任务。不可以就往后推,可以就在前面找有没有更好的方式。与其他的方法最大的不同就是它已知完成的日子去判断是否可行,而不是已知考试方式推断完成的日子。

下面是我的垃圾代码:

#include"iostream"#include"string.h"using namespace std;int n, m;int a[100010];int d[100010];int b[100010];int judge(int k){    memset(b, 0, sizeof(b));    int rest = 0; int ed = 0;    for (int i = k; i > 0; i--)    {        if (d[i] == 0 && rest != 0)            rest--;        else            if (d[i] != 0)            {                if (!b[d[i]])                {                    ed++;                    rest = rest + a[d[i]];                    b[d[i]] = 1;                }                else                {                    if (rest != 0)                        rest--;                }            }    }    if (rest != 0 || ed != m)        return false;    else        return true;}int main(){    while (cin >> n >> m)    {        memset(d, 0, sizeof(d));                     //初始化         memset(a, 0, sizeof(a));        for (int i = 1; i <= n; i++)                 //输入            cin >> d[i];        for (int i = 1; i <= m; i++)            cin >> a[i];        int s = 1, e = n;        while (s < e)        {            int mid = (e + s) / 2;                   //二分法            if (judge(mid))                e = mid;            else                s = mid+1;        }        if (judge(s))            cout << s << endl;        else            cout << "-1" << endl;    }    return 0;}

二分法哦二分法!换一种思路去简化题目!
把问题从动态的改为静态的!
虽然不知道自己这么描述对不对但是
在做题有困难的时候可以换个思路去考虑哦!
惯例:方便复制↓

#include"iostream"#include"string.h"using namespace std;int n, m;int a[100010];int d[100010];int b[100010];int judge(int k){    memset(b, 0, sizeof(b));    int rest = 0; int ed = 0;    for (int i = k; i > 0; i--)    {        if (d[i] == 0 && rest != 0)            rest--;        else            if (d[i] != 0)            {                if (!b[d[i]])                {                    ed++;                    rest = rest + a[d[i]];                    b[d[i]] = 1;                }                else                {                    if (rest != 0)                        rest--;                }            }    }    if (rest != 0 || ed != m)        return false;    else        return true;}int main(){    while (cin >> n >> m)    {        memset(d, 0, sizeof(d));        memset(a, 0, sizeof(a));        for (int i = 1; i <= n; i++)            cin >> d[i];        for (int i = 1; i <= m; i++)            cin >> a[i];        int s = 1, e = n;        while (s < e)        {            int mid = (e + s) / 2;            if (judge(mid))                e = mid;            else                s = mid+1;        }        if (judge(s))            cout << s << endl;        else            cout << "-1" << endl;    }    return 0;}
原创粉丝点击