跳转至

E - Plants vs. Zombies

Basic Information

ContestThe 2018 ICPC Asia Qingdao Regional Contest
Team AC Ratio121/373 (32.4%)

Tutorial

It is easy to think of binary search, next we need to consider how to verify the answer \(x\).

Since we must move before watering each plant, to water the first plant to height \(x\) without wasting water, we need to repeatedly move between the first and second plants. After watering the first plant, in order to water the second plant to height \(x\) without wasting water, we need to repeatedly move between the second and third plants...

Implement the above greedy process. The time complexity is \(\mathcal{O}(n\log (m \times \max a_i))\).

Solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <bits/stdc++.h>
#define MAXN ((int) 1e5)
using namespace std;

int n, A[MAXN + 10];
long long m;

// indicates the current height of each plant
long long B[MAXN + 10];

bool check(long long LIM) {
    long long step = 0;
    memset(B, 0, sizeof(long long) * (n + 3));
    for (int i = 1; i <= n; i++) {
        if (LIM > B[i]) {
            // the i-th plant needs watering
            // repeatedly move between it and the (i + 1)-th plant
            long long t = LIM - B[i];
            t = (t + A[i] - 1) / A[i];
            step += t * 2 - 1;
            // return immediately if the number of steps exceeds the limit
            // otherwise the number of steps may exceed long long
            if (step > m) return false;
            B[i + 1] += A[i + 1] * (t - 1);
        } else {
            // the i-th plant does not need watering
            // just pass by, but we still need to count the steps
            // the number of steps may exceed the limit here
            // but we won't return false as long as
            // there are no plants which need watering on the right
            step++;
        }
    }
    return true;
}

void solve() {
    scanf("%d%lld", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%d", &A[i]);

    // binary search
    long long head = 0, tail = 1e18;
    while (head < tail) {
        long long mid = (head + tail + 1) >> 1;
        if (check(mid)) head = mid;
        else tail = mid - 1;
    }
    printf("%lld\n", head);
}

int main() {
    int tcase; scanf("%d", &tcase);
    while (tcase--) solve();
    return 0;
}