2018ACM/ICPC 青岛现场赛 E题 Plants vs. Zombies

题意:

你的房子在0点,1,2,3,...,n(n<=1e5)点每个点都有一颗高度为0的花,浇一次水花会长a[i]。

你有一个机器人刚开始在你家,最多走m步,每一步只能往前走或者往后走,每走到一个地方除了房子都会给花浇水,问m步以后最低那朵花的高度最大是多少。

思路:二分,并且可以证明左右横跳(即这一个点不够我们就来回走一直到够高度为止)。

需要注意步数用完直接break,每一朵花浇够次数立刻走向下一朵花(如果还有步数)。

代码:

#include<bits/stdc++.h>
#define ll long long
#define maxn 200010
using namespace std;
ll n,m,k;
ll c[maxn],a[maxn];
ll ans,tmp,sum;
inline ll read(){
    ll x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
 
inline void print(ll x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9)
        print(x/10);
    putchar(x%10+'0');
}
bool jud(ll mid)
{
    for(int i=1;i<=n;i++) c[i]=0;
    ll cnt=m-1;c[1]=a[1];
    int i=1;
    for(;i<=n;i++)
    if(i<n){
        if(cnt==0) break;
        ll tmp=(mid-c[i]+a[i]-1)/a[i];
        if(tmp<=0) {cnt--;c[i+1]+=a[i+1];continue;}
        if(cnt<tmp*2) break;
        cnt-=tmp*2;
        c[i]+=a[i]*tmp;
        c[i+1]+=a[i+1]*tmp;
        if(cnt==0) break;
        cnt--;
        c[i+1]+=a[i+1];
        if(cnt==0) break;
    }
    else
    {
        if(cnt==0) break;
        if(c[i]>=mid) break;
        else
        {
            ll tmp=(mid-c[i]+a[i]-1)/a[i];
            if(cnt<tmp*2) return 0;
            else c[i]+=a[i]*tmp;
        }
    }
    for(;i<=n;i++)if(c[i]<mid) return 0;
    return 1;
}
int main()
{
    ll T,cas=1;
    T=read();
    while(T--)
    {
        n=read();m=read();
        ll l=0,r=m;
        for(int i=1;i<=n;i++)
        {a[i]=read();
        if(r<m*a[i]) r=m*a[i];
        }
        if(m==0) {puts("0");continue;}
        ll ans=r;
        while(l<r)
        {
            ll mid=(l+r)/2;
            if(jud(mid)) {l=mid+1;ans=mid;}
            else r=mid;
        }
        print(ans);
        putchar('\n');
    }
    return 0;
}

 

posted @ 2018-11-12 17:22  unknownname  阅读(301)  评论(0编辑  收藏  举报