Codeforce 1260 D.A Game with Traps(二分+贪心)

题目链接: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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章