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

}


内容概要:本文详细记录了对一个Android ARM64静态ELF文件中字符串加密机制的逆向分析过程。该ELF文件的所有字符串均被加密,无法通过常规strings命令或IDA直接识别。作者通过分析发现,加密字符串存储在.rodata段,其解密所需信息(包括密文地址、长度和16位密钥)保存在.data.rel.ro段的40字节描述符中。核心解密函数sub_10F408采用自反的双pass流密码算法,结合固定密钥KEY_TERM(由.data段24字节数据计算得出),实现字节级非线性、位置与长度相关的加密。文章还复现了完整的Python解密脚本,并揭示了该保护机制的本质为代码混淆而非强加密,最终成功批量解密全部956条字符串,暴露程序真实行为,如shell命令模板、设备标识篡改、网络重置等操作。此外,文中还提及未启用的自定义壳框架及其反dump设计。; 适合人群:具备逆向工程基础的安全研究人员、二进制分析人员及对ELF保护技术感兴趣的开发者。; 使用场景及目标:①学习ELF二进制中字符串加密的典型实现方式与逆向突破口;②掌握从结构识别、函数追踪到算法还原的完整逆向流程;③理解“绑定二进制”的完整性校验设计及其局限性;④实践编写IDAPython脚本自动化提取与解密敏感数据。; 阅读建议:此资源以实战案例驱动,不仅展示技术细节,更强调逆向思维与验证方法,建议读者结合IDA调试环境,逐步跟随文中步骤进行动态分析与算法验证,深入理解每一步的推理依据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值