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$ 倍,很容易证明最后的答案是不会超过这个值的。

猜你喜欢

转载自www.cnblogs.com/dilthey/p/9941711.html