Plants vs. Zombies(二分)

    科技2022-08-05  151

    文章目录

    [Plants vs. Zombies](https://zoj.pintia.cn/problem-sets/91827364500/problems/91827370312)题意解题思路代码

    Plants vs. Zombies

    题意

    给以n个数,每个数表示浇一次水可以长高多少,你一共可以移动m次,每次移动只能移动一格,移动一次浇一次水,问你m次以后最小值最大是多少

    解题思路

    这个题刚开始看到没一点思路,仔细一想就是二分了,我们二分最小值最大是多少,每次check的时候当这个位置没有check值大,我们就浇这个,并且向后移动再回来,这样一直check下去,如果最后步数不够用就说明check值太大了。 有个细节就是最后一步要特判,因为有可能给倒数第二个位置浇水的时候顺便给他浇的满足情况了;

    代码

    #include<bits/stdc++.h> using namespace std; #define ll long long const ll mod=1000000007; const int mx=100100; ll n,m; ll a[mx]; bool check(ll x){ ll tem=m; ll y=0,cnt; // y表示浇上一步 顺便给下一步浇了几次 ll res; for(int i=1;i<n;i++){ cnt=a[i]*(y+1); tem--;//走到这个位置就需要花费一步 if(cnt<x){ res=x-cnt; y=(res+a[i]-1)/a[i]; // 减去使得这个位置满足情况的 步数 tem=tem-y*2LL; if(tem<0) return 0; } else{ y=0; } } // 特判 最后一步 // 如果小于 x 需要浇水 否则就不需要 if(a[n]*y<x){ tem--; res=x-(a[n]*y+a[n]); y=(res+a[n]-1)/a[n]; tem-=y*2; } // 如果tem 小于0说明步数不够用了 return tem>=0; } int main(){ ios::sync_with_stdio(0); int _; cin>>_; while(_--){ cin>>n>>m; ll ma=0; for(int i=1;i<=n;i++){ cin>>a[i]; ma=max(ma,a[i]); } // 如果 m<n 肯定不可能的 if(m<n) { cout<<"0\n"; continue; } ll l=0LL,r=m*ma+7; ll mid,ans=0; while(l<=r){ mid=(l+r)/(ll)2; if(check(mid)){ ans=mid; l=mid+1LL; }else{ r=mid-1LL; } } cout<<ans<<"\n"; } return 0; }
    Processed: 0.021, SQL: 8