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.

传送门:CF732D

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.

Sample Input

1
2
3
7 2
0 1 0 2 1 0 2
2 1

Sample Output

1
5

题解

首先是如何判断在第a天能考完所有科目,这里有一个函数judge(int a)。这道题很重要的一个思想就是从后往前判断而不是从前往后判断,因为一场考试可能有多个天数可以考,但考试天数处于后面的拥有的复习天数总是比天数处于前面的要多,所以从后往前考虑不会有问题。但如果从前往后考虑,就会出现本来考试的那天其实是用来复习的问题。 那么如何判断第a天能考完所有科目那,我们需要一个数组来标记每门学科是否被考过,一个sum来储存我们需要复习的天数,还有一个v变量储存考过的学科的数量。 然后我们从第a天到第1天遍历,如果那天可以考试,即day[i]>0且那天考得科目还没有考过即&&used[day[i]]==false,那么我们选择在那天考试,然后sum+=sub[day[i]],并且将那门学科标记为考过,即used[day[i]]=true,然后v++。 如果那天不可以考试或者那天考得科目已经考过,我们就判断sum,如果sum>0,(即我们还需要天数去复习),就sum--。 最后判断是否sum<=0(即有足够的天数去复习)&&v==m(考过所有科目),那么第a天就是符合能考完所有科目的天数。 然后的问题就是找最小的天数了,又因为这道题的数据达到了10^5,显然,如果遍历所有天数的话,复杂度将达到O(n^2)显然会超时,所以我们这里用二分查找来降低复杂度,使之变成O(nlog(n))。
## AC code:(不包含输入类)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//package D2;  
import java.io.*;
import java.util.*;
public class Main {
static boolean[] used;
static int day[];
static int sub[];
static int m;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
int n=sc.nextInt();
m=sc.nextInt();
day=new int [n+1];
sub=new int [m+1];
for(int i=1;i<=n;i++){
day[i]=sc.nextInt();
}
for(int i=1;i<=m;i++){
sub[i]=sc.nextInt();
}
int flag=0;
int jg=0;
//遍历复杂度太高
/*for(int i=1;i<=n;i++){
if(judge(i)){
flag=1;
jg=i;
break;
}
}*/
int start = 1;
int end = n;
while(start<=end){
int mid=(start+end)/2;
if(judge(mid)){//如果找到,就往左边找
end=mid-1;
flag=1;//标记
jg=mid;//记录结果,其实可以省略
}
else{
start=mid+1;
}
}
if(flag==1){
System.out.println(jg);
}
else
System.out.println(-1);
}
}
public static boolean judge(int a){
int v=0,sum=0,count=0;
used=new boolean[100005];//记录科目是否考过的数组
for(int i=a;i>=1;i--){
if(day[i]>0&&used[day[i]]==false){//如果那天可以考且那门课没有考过
sum+=sub[day[i]];//记录需要复习的天数
used[day[i]]=true;//把那门课设置为已考过
count++;//记录考过的科目数
}
else if(sum>0){//注意这里有坑 需先判断sum>0,如果不判断的话,会出现sum=0时明明不需要复习了,你却依旧把那天进行复习
sum--;
}
}
if(sum<=0&&count==m){
return true;
}
else
return false;
}

}