版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}