Exams Codeforces Round#377-D(贪心+二分)

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.

题解:

首先是如何判断在第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:

//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;
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值