ZOJ4062 Plants vs. Zombies(二分+贪心)

题目链接:传送门

题目大意:

  有n棵植物依次放在1-n,机器人从0出发浇水,每棵植物被浇水时di += ai,求浇m次水后min{di|1 ≤ i ≤ n}的最大值。(浇水时必须往左或往右走一步,落脚点为浇水点)

思路:

  若已知答案mid(滑稽脸):可以贪心地从左到右浇水,反复给di和di+1浇水,直到当前的di ≥ mid。。。O(n)。。。既然可以O(n)验证答案,那就开心地二分掉了。

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAX_N = 1e5 + 5;

int N;
ll M;
ll a[MAX_N];
ll d[MAX_N];

bool judge(ll mid) {
    for (int i = 1; i <= N; i++) d[i] = 0;
    ll cnt = 0, jumped = 0;
    for (int i = 1; i <= N; i++) {
        if (d[i] >= mid) {
            jumped++;
            continue;
        }
        cnt += jumped; jumped = 0;
        ll mul = (mid-d[i])/a[i] + ((mid-d[i])%a[i] > 0);
        cnt += mul*2-1;
        d[i] += mul * a[i];
        if (i+1 <= N)
            d[i+1] += (mul-1) * a[i+1];
    }
    return cnt <= M;
}

int main()
{
    int T;
    cin >> T;
    while (T--) {
        scanf("%d%lld", &N, &M);
        ll _max = 0;
        for (int i = 1; i <= N; i++) {
            scanf("%lld", a+i);
            _max = max(_max, a[i]);
        }

        ll l = 0, r = _max*M;
        ll ans = 0;
        while (l <= r) {
            ll mid = (l+r) >> 1;
            if (judge(mid)) {
                ans = max(ans, mid);
                l = mid+1;
            }
            else
                r = mid-1;
        }
        cout << ans << endl;
    }
    return 0;
}
/*
2
4 8
3 2 6 6
3 9
10 10 1
*/
View Code

猜你喜欢

转载自www.cnblogs.com/Lubixiaosi-Zhaocao/p/9941467.html