題目連接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4062ios
題意:c++
如今在一條 $x$ 軸上玩植物大戰殭屍,有 $n$ 個植物,編號爲 $1 \sim n$,第 $i$ 個植物的位置在座標 $i$,成長值爲 $a_i$,初始防護值爲 $d_i$。函數
如今有一輛小車從座標 $0$ 出發,每次澆水操做必須是先走 $1$ 單位長度,而後再進行澆水,植物被澆一次水,防護值 $d_i+=a_i$。spa
如今知道,小車最多進行 $m$ 次澆水操做,而已知總防護值爲 $min{d_1,d_2,d_3,\cdots,d_n}$。求最大的總防護值爲多少。code
Inputblog
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:ip
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.ci
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.get
It's guaranteed that the sum of in all test cases will not exceed $10^6$.input
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<<'\n'; } }
注:
這題的右區間不要直接設成 $1e17$,由於這樣當 $a[i]$ 都是小數據的時候 $judge$ 函數裏的 $cnt$ 會爆long long。
不妨設成 $a_i$ 最小值的 $m$ 倍,很容易證實最後的答案是不會超過這個值的。