1. 程式人生 > >ZOJ4062 Plants vs. Zombies(二分+貪心)

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