题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4062
题意:
现在在一条 $x$ 轴上玩植物大战僵尸,有 $n$ 个植物,编号为 $1 sim n$,第 $i$ 个植物的位置在坐标 $i$,成长值为 $a_i$,初始防御值为 $d_i$。
现在有一辆小车从坐标 $0$ 出发,每次浇水操作必须是先走 $1$ 单位长度,然后再进行浇水,植物被浇一次水,防御值 $d_i+=a_i$。
现在知道,小车最多进行 $m$ 次浇水操作,而已知总防御值为 $min{d_1,d_2,d_3,cdots,d_n}$。求最大的总防御值为多少。
Input
There are multiple test cases. The first line of the input contains an integer $T$, indicating the number of test cases. For each test case:
The first line contains two integers $n$ and $m$ ($2 le n le 10^5, 0 le m le 10^{12}$), indicating the number of plants and the maximum number of steps the robot can take.
The second line contains integers $a_1,a_2, cdots, a_n$ ($1 le a_i le 10^5$), where indicates the growth speed of the -th plant.
It's guaranteed that the sum of in all test cases will not exceed $10^6$.
Output
For each test case output one line containing one integer, indicating the maximum defense value of the garden DreamGrid can get.
Sample Input
2
4 8
3 2 6 6
3 9
10 10 1
Sample Output
6
4
题解:
二分总防御值,对于固定的防御值 $d$,显然花园里的每个植物都要不小于 $d$,因此贪心地从左往右寻找每一个防御值小于 $d$ 的植物,对它和它右侧的植物反复浇水。
AC代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1e5+10; int n; ll m; ll a[maxn],d[maxn]; ll judge(ll k) { memset(d,0,(n+1)*sizeof(ll)); ll cnt=0; for(int i=1;i<=n;i++) { if(i==n && d[i]>=k) break; cnt++, d[i]+=a[i]; if(d[i]>=k) continue; ll tmp=(k-d[i])/a[i]+((k-d[i])%a[i]>0); cnt+=2*tmp; d[i]+=tmp*a[i]; d[i+1]+=tmp*a[i+1]; } return cnt; } int main() { ios::sync_with_stdio(0); cin.tie(0); int T; cin>>T; while(T--) { cin>>n>>m; ll mn=1e5+10; for(int i=1;i<=n;i++) cin>>a[i], mn=min(mn,a[i]); ll l=0, r=mn*m; while(l<r) { ll mid=(l+r+1)>>1; if(judge(mid)<=m) l=mid; else r=mid-1; } cout<<l<<' '; } }
注:
这题的右区间不要直接设成 $1e17$,因为这样当 $a[i]$ 都是小数据的时候 $judge$ 函数里的 $cnt$ 会爆long long。
不妨设成 $a_i$ 最小值的 $m$ 倍,很容易证明最后的答案是不会超过这个值的。