E - Plants vs. Zombies ZOJ - 4062 -二分(最小值最大化)

  • E - Plants vs. Zombies

  •  ZOJ - 4062 
  • 题意:机器人走过一个花,可以给那个花浇水,给定步数下,问花的最小的最大能量值
  • 思路:最大化最小值常见二分类型。直接二分答案,然后从前往后计算每个点满足答案要多少次。
  • 我们跟它右边那个反复跳即可。这样的话每一次check先预处理出实际应该遍历这个点几次,
  • 到达一个点时先sum++,因为第一次总是要从前面过来的,不是在后面循环过程中凑出来的,
  • 每次都是向右循环凑次数:
  • sum+=(b[i]-1)*2

  • 所以每一次需要走的次数应当减去上次循环过程中已经走过的,
  • b[i+1]-=(b[i]-1);

  • 然后记录需要使用跳多少次即可。最后只需判断次数是否大于m即可,
  • 如果到了最后需要判断是否需要sum++ 
  • if(i==n&&b[i]<1)break;

  • #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define maxn 123456
    int t,n,a[maxn],maxx;
    ll m,l,r,mid,b[maxn];
    bool check(ll middle)
    {
        ll sum=0;
        for(int i=1; i<=n; i++)
            b[i]=(middle%a[i]==0?middle/a[i]:middle/a[i]+1);
        for(int i=1; i<=n; i++)
        {
            if(i==n&&b[i]<1)break;
            sum++;
            if(b[i]>1)
            {
                sum+=(b[i]-1)*2;
                b[i+1]-=(b[i]-1);
            }
            if(sum>m)return false;
        }
        return true;
    }
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            l=r=maxx=0;
            scanf("%d%lld",&n,&m);
            for(int i=1; i<=n; i++)
            {
                scanf("%d",&a[i]);
                if(a[i]>maxx)
                    maxx=a[i];
            }
            r=maxx*m;
            while(l<r)
            {
                mid=(r+l+1)/2;
                if(check(mid))l=mid;
                else r=mid-1;
            }
            printf("%lld\n",r);
        }
        return 0;
    }
    

猜你喜欢

转载自blog.csdn.net/BePosit/article/details/83929892