Educational Codeforces Round 77 (Rated for Div. 2) - D. A Game with Traps(二分)

题意:$m$个士兵,每个士兵都有一个灵敏度$a[i]$,起点为$0$,终点为$n + 1$,在路上有$k$个陷阱,每个陷阱有三个属性$l[i],r[i],d[i]$,$l[i]$表示陷阱的位置,如果你走到$r[i]$这个位置,则可以拆掉这个陷阱,$d[i]$与士兵的灵敏度对应,如果$d[i]>a[j]$,则这个士兵就会被困住,现在你可以挑选任意数量的士兵,你有两种方式移动方式:

  • 带着士兵移动,但士兵不能被陷阱困住,每秒只能移动一格,从$x$到$x+1$或者$x-1$
  • 一个人去拆除陷阱$($你不会被陷阱困住$)$,每秒移动一格,从$x$到$x+1$或者$x-1$

问你最多可以带多少士兵,在时间$t$内移动到终点

思路:二分答案或者二分可以挑选士兵的最小灵敏度都可以,每次贪心带灵敏度最高的士兵,关键是二分后如何计算移动的最小时间,显然当多个陷阱的$l[i],r[i]$有交叉时,应该一个人继续前进拆除陷阱,直到$l[i],r[i]$没有交叉时回到士兵的位置带着士兵前进,否则直接回到士兵的位置,直到再次遇到能困住士兵的陷阱,一直这样到终点,$l[i],r[i]$相互交叉的部分则可以用差分、前缀和来处理,记录每个点的覆盖情况,计算被覆盖区间的总长度。

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;

const int N = 200010;

struct node {
    int l, r, d;
};

int a[N], cnt[N];
int n, m, k, t;
node p[N];

bool cmp(int a, int b)
{
    return a > b;
}

bool check(int mid)
{
    int imin = a[mid], tt = 0;
    for (int i = 1; i <= n + 1; i++) cnt[i] = 0;
    for (int i = 1; i <= k; i++)
        if (p[i].d > imin)
            cnt[p[i].l]++, cnt[p[i].r + 1]--;
    for (int i = 1; i <= n + 1; i++) cnt[i] += cnt[i - 1];
    for (int i = 1; i <= n + 1; i++)
        if (cnt[i] >= 1) tt++;
    tt = 2 * tt + n + 1;
    return tt > t;
}

int main()
{
    scanf("%d%d%d%d", &m, &n, &k, &t);
    for (int i = 1; i <= m; i++)
        scanf("%d", &a[i]);
    for (int i = 1; i <= k; i++)
        scanf("%d%d%d", &p[i].l, &p[i].r, &p[i].d);
    sort(a + 1, a + m + 1, cmp);
    int l = 0, r = m;
    while (l < r) {
        int mid = (l + r + 1) >> 1;
        if (check(mid)) r = mid - 1;
        else l = mid;
    }
    printf("%d\n", l);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zzzzzzy/p/12097558.html