http://codeforces.com/contest/1260/problem/D
题意:
你m个士兵,每个士兵都有敏捷值
有k个陷阱,每个陷阱有3个属性:l,r,dangerous,其中:
l:若你的士兵敏捷值小于dangerous,那么你带领士兵经过这个点就会当场去世
r:为了避免你的士兵当场去世,你可以先自己走到r点,此时陷阱就会失效
士兵必须跟着你一起走,你可以先选择自己去破坏陷阱,然后回来带着士兵走
你的任务是带领士兵从0点走到n+1这个点,你每走一格就会花费1s
问:在t秒内(包括t秒),你最多能带多少个士兵前往n+1这个点
题解:
首先士兵应该要按灵活值排序,灵活值高的士兵优先带
下面只考虑危险值大于所带士兵最小灵活性的陷阱
销毁陷阱大概有3种方法:
1.对于每个陷阱都先自己走到r销毁,然后倒过来带士兵走
2.先一次性将所有陷阱踩完,然后带着士兵一次性通过
前面两种方法都不是最优
比如对于这3个陷阱
L1= 2 R1= 5
L2= 4 R2= 6
L3= 8 R3= 9
两种走法分别:
走法1: 32s 走法2: 27s
还有一种走法:
第三种走法就是:
对于l,r有重叠的区间,看成一个大区间,一次性走完,然后分别走完各个大区间
使用区间前缀和处理区间叠加问题
然后二分答案即可
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 2e5 + 7;
int n, m, k, t;
int num[maxn], flag[maxn];
struct node {
int l, r, v;
}trap[maxn];
bool cmp(int a, int b) {
return a > b;
}
bool check(int rk) {
for (int i = 1; i <= k; i++)
if (trap[i].v > rk) { //区间前缀和
flag[trap[i].l]++;
flag[trap[i].r + 1]--;
}
int hav = 0, sum = 0;
for (int i = 1; i <= n + 1; i++) {
hav += flag[i];
flag[i] = 0;//memset
if (hav) //假如当前被区间覆盖,那么说明这个格子需要走3次
sum += 3;
else //否则带队一次过即可
sum += 1;
}
if (sum <= t)
return 1;
else
return 0;
}
int main() {
cin >> m >> n >> k >> t;
for (int i = 1; i <= m; i++)
scanf("%d", num + i);
sort(num + 1, num + 1 + m, cmp);//从大到小排序
for (int i = 1; i <= k; i++)
scanf("%d %d %d", &trap[i].l, &trap[i].r, &trap[i].v);
int l = 0, r = m;
while (l < r) { //二分答案
int mid = (l + r + 1) >> 1;
if (check(num[mid]))
l = mid;
else
r = mid - 1;
}
cout << l << endl;
return 0;
}