1. 程式人生 > >ZOJ 4062 - Plants vs. Zombies - [二分+貪心][2018 ACM-ICPC Asia Qingdao Regional Problem E]

ZOJ 4062 - Plants vs. Zombies - [二分+貪心][2018 ACM-ICPC Asia Qingdao Regional Problem E]

題目連結: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<<'\n';
    }
}

注:

這題的右區間不要直接設成 $1e17$,因為這樣當 $a[i]$ 都是小資料的時候 $judge$ 函式裡的 $cnt$ 會爆long long。

不妨設成 $a_i$ 最小值的 $m$ 倍,很容易證明最後的答案是不會超過這個值的。