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

D. A Game with Traps

题意:

给你一群士兵(每个士兵有灵活值 a i a_i ai
给出地雷的信息(地雷的位置,解锁地雷位置,士兵躲避地雷的最低灵活值)
你是将军,可以到解锁地雷的位置解锁地雷然后再回去带兵通过雷区。
问在t时间内,你最多能带多少个兵。
(注意:兵一定得有将军带才能行动)
样例:
5(士兵的数量) 6(离目的地还有多远) 4(炸弹的数量) 14(时限)
1 2 3 4 5 (第i位士兵的灵活值)
1 5 2 (第1位置上有地雷,到第5能消除,躲避地雷的最低灵活值为2)
1 2 5 (。。以此类推)
2 3 5
3 5 3
输出
3

带3,4,5,将军先到3消除掉第二和第三个炸弹t=3,然后回去t=6带兵到达目的地t=13。

思路:

很容易想到二分士兵的灵活值。之后就是如何写judge函数。
这时候就要判断一种将军走的最优策略。
主要的问题是将军走到那时候就回去带兵。
这时候有两种情况。
一、
Codeforces Educational Codeforces Round 77 (Rated for Div. 2)(D. A Game with Traps)_第1张图片
一解锁返回 3 ∗ x 1 + x 2 + 3 ∗ x 3 3*x_1+x_2+3*x_3 3x1+x2+3x3
二解锁返回 3 ∗ x 1 + 3 ∗ x 2 + 3 ∗ x 3 3*x_1+3*x_2+3*x_3 3x1+3x2+3x3
很明显这时候将军只要到1解锁的位置就可以返回了,不然会多跑1解锁到2位置的距离。即 3 ∗ x 1 + x 2 + 3 ∗ x 3 3*x_1+x_2+3*x_3 3x1+x2+3x3
二、
Codeforces Educational Codeforces Round 77 (Rated for Div. 2)(D. A Game with Traps)_第2张图片
一解锁返回 3 ∗ x 1 + 5 ∗ x 2 + 3 ∗ x 3 3*x_1+5*x_2+3*x_3 3x1+5x2+3x3
二解锁返回 3 ∗ x 1 + 3 ∗ x 2 + 3 ∗ x 3 3*x_1+3*x_2+3*x_3 3x1+3x2+3x3
这时候将军要跑到2解锁的位置再回来才是最优。不然会多跑一段 x 2 x_2 x2

所以就是跑到目前将军接触到地雷的最远解锁位置,然后再返回。

这里可以用差分来做。
当sum为0的时候就返回,不为0就得跑3次,为0跑一次。具体如代码:

#include 
using namespace std;
const int maxn = 3e5;
typedef long long ll;

int a[maxn], l[maxn], r[maxn], d[maxn];
int sum[maxn];
int n, m, k, t;
bool judge(int v) {
    memset(sum, 0, sizeof(sum));
    for (int i = 0; i < k; i++)
        if (d[i] > v) {  //差分
            sum[l[i]]++;
            sum[r[i] + 1]--;
        }
    int res = 1;
    for (int i = 1; i <= n; i++) {
        sum[i] += sum[i - 1]; 
        res++;
        if (sum[i])
            res += 2;
    }
    return res <= t;
}

main() {
    scanf("%d %d %d %d", &m, &n, &k, &t);
    int maxx = -1;
    for (int i = 1; i <= m; i++) {
        scanf("%d", &a[i]);
        maxx = max(maxx, a[i]);
    }
    for (int i = 0; i < k; i++)
        scanf("%d%d%d", &l[i], &r[i], &d[i]);
    sort(a + 1, a + 1 + m);
    int r = maxx + 1; //这里得加1,血与泪的教训
    int l = 0;
    int mid;
    while (r > l) {
        mid = (r + l) / 2;
        if (judge(mid)) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }
    int cnt = 0;
    for (int i = 1; i <= m; i++) {
        if (a[i] >= l)
            cnt++;
    }
    cout << cnt << endl;
}

你可能感兴趣的:(思维)