The 2018 ACM-ICPC Asia Qingdao Regional Contest E Plants vs. Zombies(ZOJ 4062)

题目链接:https://zoj.pintia.cn/problem-sets/91827364500/problems/91827370312

题意:你家右边有n块土地,每块土地相隔1米,第一块土地离家也相隔1米,现在你的机器人从家开始去给土地浇水,机器人每移动1米就浇一次水,第i块土地每浇一次水就会增加a[i]的防御值,整体防御值是n块土地中最小的防御值,现在你的机器人只能走m米,问你走完m米后,整体防御值最大可能为多少。

思路:防御值最大化可以想到二分,最小l=0,最大r=1e17,然后对于第i块土地,那肯定机器人是在i和i+1之间来回移动,直到第i块土地达到相应的值,相应的第i+1块土地也会增加浇水次数。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
typedef long long ll;
using namespace std;
ll a[200005];
ll fun(ll mid,ll n,ll m)
{
    ll sum=0;
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        ll x=mid/a[i];
        if(mid%a[i]!=0)
            x++;
        if(x<=sum)//第i已经达到了mid
        {
            sum=0;
            if(i<n)//当i<n时,还是要从第i-1移动到第i,当i==n时,就都已经达到mid了,就没必要移动
               ans++;
        }
        else
        {
            x-=sum;//所需要的次数减去已经浇水次数
            ans=ans+2*x-1;//浇完第i块所需次数
            sum=x-1;//相应的给第i+1块浇了sum次
        }
        if(ans>m)//如果ans已经大于m了,那肯定是不可以了
            return 0;
    }
    if(ans>m)
        return 0;
    return 1;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ll n,m;
        scanf("%lld%lld",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        ll l=0,r=100000000000000007;
        ll ans;
        while(l<=r)
        {
            ll mid=(l+r)/2;
            if(mid==0)//mid=0是肯定成立的,但带到fun函数里就不一定成立了
            {
                ans=mid;
                l=mid+1;
                continue;
            }
            if(fun(mid,n,m)==1)
            {
                ans=mid;
                l=mid+1;
            }
            else
                r=mid-1;
        }
        printf("%lld\n",ans);
    }
}

猜你喜欢

转载自www.cnblogs.com/zcb123456789/p/12336351.html