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)验证答案,那就开心地二分掉了。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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 */