題目鏈接:https://codeforces.com/contest/1260/problem/D
題目大意:
一個長度爲n+1的直線上有k個陷阱,每個陷阱描述爲{l,r,v},表示這個陷阱的起始點l,終止點r,力量值v,你有m個士兵,每個士兵有一個能力值ai,當ai<vi時表示士兵i不能越過陷阱i,但是你可以走過去,當你經過位置ri時,陷阱i就消失了,初始時你們都在位置0,現在要去位置n+1,你現在必須選擇一些士兵,你攜帶着他們通過所有的障礙到達n+1,且必須在規定的時間t內完成,注意,如果想讓士兵移動,你必須和士兵在同一位置,也就是你清除了障礙物ri,你必須回到li-1帶上你的軍隊一起出發,問你最後能帶的最多的士兵的數量。
思路:
二分帶的最小的士兵能力值mid,然後驗證是否能在t時間內送過去。
顯然,如果沒有陷阱,我肯定帶着軍隊一起走最優,如果有陷阱,我肯定先把當前這個陷阱排除掉,再回去帶着軍隊走,這樣肯定最優(畫畫圖就知道了)。
所以,我們將陷阱按照左端點排序,如果陷阱i和陷阱i+1有重合,那麼我肯定只要從li走到max(ri,ri+1)就好了,否則我們就正常的走,這就是個簡單模擬過程。
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int a[maxn];
int l[maxn],r[maxn],d[maxn];
int m,n,k,t;
bool judge(int mid){
int mx=a[mid];
set<pair<int,int> >st;
for(int i=1;i<=k;i++){
if(d[i]>mx){
st.insert({l[i],r[i]});
}
}
int cur=0;
int tim=0;
for(auto it=st.begin();it!=st.end();it++){
auto now=*it;
if(now.first<=cur){//如果當前陷阱位置在位置的後面,繼續往前走
tim=tim+max(0,now.second-cur);
cur=max(cur,now.second);
}
else{
//否則我必須走到下一個陷阱的前面去
tim=tim+now.second-now.first+1;
cur=now.second;
}
}
tim=tim*2+n+1;
return tim<=t;
}
signed main(){
scanf("%d%d%d%d",&m,&n,&k,&t);
for(int i=1;i<=m;i++){
scanf("%d",&a[i]);
}
sort(a+1,a+m+1);
for(int i=1;i<=k;i++){
scanf("%d%d%d",&l[i],&r[i],&d[i]);
}
int l=1,r=m;
int ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(judge(mid)){
ans=m-mid+1;
r=mid-1;
}
else{
l=mid+1;
}
}
printf("%d\n",ans);
return 0;
}