codeforces ECR77 div2 A Game with Traps(二分,线段覆盖)

题目大意:

有m个士兵通过长度为n+1的道路,可是道路上有k个陷阱。每个陷阱都有危险程度,若士兵的能力没达到对应危险程度,那么这个士兵不能够通过这个陷阱。你是一个教官,教官能去拆陷阱,每个陷阱有li ri 和di(ri>=li) 分别表示陷阱的位置,拆陷阱的位置。di是危险程度。教官不会被陷阱干掉。问你最多可以带多少个士兵在t秒内完成n+1的道路。

解题思路:

难点1:首先,我们要想到用二分处理。本题满足二分的true true true false false结构,所以我们可以对答案进行二分。

难点2:知道本次需要带多少个士兵了。怎么拆陷阱才能最优呢?这里,我们需要抽象出一个区间模型。把每一个陷阱抽象为[li,ri]的区间。对于没有相交的区间,我们拆陷阱所需要的时间为:(ri-li+1)*2,就是教官走到陷阱前然后来回走一遍嘛。对于有相交的区间,我们走到区间的并的最右端点,为什么这样最优呢?大家画图看一下就知道,这样走可以使得教官免去了(l2-l1)*2这个距离。

难点3:怎么实现?很自然地我们有n^2做法,实打实的遍历陷阱,然后询问和它并的区间,然后一次erase掉数个陷阱。但是,这样不行,会t。需要想一个n的做法。其实我们还是遍历陷阱,但是这时候,我们维护一个量,就是本次这个陷阱走到最远的地方。假如本个区间和上一个区间没有相交,我们认为这次走到了本个陷阱的ri位置。若本个陷阱和上一个陷阱有相交,有两种情况。第一是这个陷阱的ri小于当前的位置,我们就不更新本次位置,而且不用拆陷阱,因为上次拆陷阱顺路帮你拆了。假若ri大于当前的位置,我们就去拆这个陷阱,更新为这个更远的位置,就相当于我们之前说的走去了更远的位置。

这里关键是要懂得维护走到最远的距离这个量。

#include <bits/stdc++.h>
using namespace std;
int m,n,k,t;
vector<int> amv;
vector<int> l;
vector<int> r;
vector<int> d;
bool can(int x){
	int mina=amv[x-1];
	vector<pair<int,int> > trap;
	for(int i=0;i<k;i++){
		if(d[i]>mina){
			trap.push_back(make_pair(l[i],r[i]));
		}
	}
	sort(trap.begin(),trap.end());
	int laspos=0;
	int time=0;
	for(int i=0;i<(int)trap.size();i++){
		if(trap[i].first>laspos){
			time+=trap[i].second-trap[i].first+1;
			laspos=trap[i].second;
		}else{
			time+=max(trap[i].second-laspos,0);
			laspos=max(laspos,trap[i].second);
		}
	}
	return (2*time+(n+1))<=t;
}
int main(){
	cin>>m>>n>>k>>t;
	amv.resize(m,0);
	l.resize(k,0);
	r.resize(k,0);
	d.resize(k,0);
	for(int i=0;i<m;i++){cin>>amv[i];}
	sort(amv.begin(),amv.end(),greater<int>());
	for(int i=0;i<k;i++)cin>>l[i]>>r[i]>>d[i];
	int x=0;
	int y=m+1;
	while(x+1<y){	
		int m=x+(y-x)/2;
		if(can(m))x=m;	
		else y=m;
	}
	cout<<x<<endl;	
	return 0;
}
发布了171 篇原创文章 · 获赞 4 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/FrostMonarch/article/details/103330773
今日推荐