Codeforces Round #377 (Div. 2)-D. Exams

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/C_13579/article/details/81875629

地址:http://codeforces.com/contest/732/problem/D

思路:开始我考虑从头开始遍历,发现这样根本行不通,然后从后考虑发现是可以判断是否可以考完全部课程,而n<=10^5,因此可以二分答案来求解。 在二分答案 h 时,首先将 sp=所有考试所需要的休息天数和,s=考试课程数,p=0,由a[h]到a[1]遍历,当发现有一门课 t 没有考时,sp-=休息天数d[t],p+=d[t], --s,同时标记该课程t; 这个p是用来保存已考的课程所需的休息天数,之所以要单独分开,是由于 当 课程 t 前面有大于d[t] 的天数时, 其他的空余天数是没有用处的。 在判断 所剩的天数是否可以将剩下的考试考完即可, 最后遍历完还需判断所有考试是否考完(即 s是否为0)

Code :

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

const int MAX_N=100005;
const int MAX_M=100005;
int n,m,sum;
int a[MAX_N],d[MAX_M];
bool boo[MAX_M];

bool Find(int h);
int main()
{
	ios::sync_with_stdio(false);
	while(cin>>n>>m){
		for(int i=1;i<=n;++i)
			cin>>a[i];
		sum=0;
		for(int i=1;i<=m;++i)
		{
			cin>>d[i];
			sum+=d[i];
		}
		int l=m,r=n;
		while(l<=r){
			int h=(l+r)/2;
			if(Find(h)==true)	r=h-1;
			else	l=h+1; 
		}
		if(l>n)	l=-1;
		cout<<l<<endl;
	}
	
	return 0;
}

bool Find(int h)
{
	bool bo=true;
	int sp=sum,p=0,s=m;
	memset(boo,0,sizeof(boo));
	while(h>0&&!a[h]){
		--h;
	}
	while(h>0){
		int t=a[h--];
		if(t&&boo[t]==false){
			boo[t]=true;
			sp-=d[t];	p+=d[t];	--s;
			if(sp+p+s>h){
				bo=false;	break;
			}
			if(!s)	break;
		}else	p=max(0,p-1);
	}
	if(s)	bo=false;	//还有课程没考 
	return bo;
}

猜你喜欢

转载自blog.csdn.net/C_13579/article/details/81875629