原题链接
题意:m个士兵敏捷值为ai,有k个陷阱,每个陷阱有l,r,d三个属性,l代表陷阱的位置,r是可以使陷阱失效的位置,士兵敏捷值不小于d的才可以经过l,现在你和m个士兵位于坐标轴0点,boss位于n+1点,每次单独移动和带士兵移动一格(左右)花费的时间为1,经过即可以拆除陷阱不花费时间。求在时间t内最多能带多少个士兵到boss点。
思想:二分,将所有的陷阱区间对左端点进行排序,然后二分计算如何将花费时间在范围内最大化。核心选择:b[i].d<=mid||b[i].r<=mx这样一来对于低于他的直接跳过(不改变mx),如果有两个陷阱 [ 1 10 5 ] [ 5 7 100 ],是否存在直接拆除第一个陷阱而直接忽略第二个陷阱而影响结果呢?最优解三种情况1、全体小于5这时,需要跨过两个,由于重复导致只需拆除第一个。2、大于5,直接忽略第一个陷阱,拆除第二个陷阱。3、大于100,都跨过过没有任何影响。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct Node
{
int l,r,d;
bool operator<(Node a)const{
return l<a.l;
}
}b[200001];
int a[200112],n,m,k,t;
int main()
{
cin>>m>>n>>k>>t;
for(int i=1;i<=m;i++){
scanf("%d",&a[i]);
}
for(int i=0;i<k;i++){
scanf("%d%d%d",&b[i].l,&b[i].r,&b[i].d);
}
sort(b,b+k);
int l=0,r=201010;
int c,mx;
while(l<r){
int mid=(l+r)>>1;
c=n+1,mx=0;
for(int i=0;i<k;i++){
if(b[i].d<=mid||b[i].r<=mx) continue;
mx=max(mx,b[i].l-1);
c+=(b[i].r-mx)*2;
mx=b[i].r;
}
if(c>t) l=mid+1;
else r=mid;
}
int ans=0;
for(int i=1;i<=m;i++){
ans+=(a[i]>=l);
}
printf("%d\n",ans);
}
总结;二分不是太熟练,是巨菜。