Live2d Test Env

Gym - 100851L:Landscape Improved (二分+单调性)

题意: 一个宽度为N的网格图,i上有h[i]高的方块。现在你有W个方块,问怎么放使得最终的最高点最高。

     当一个格子的下方,左下方和右下方都有方块那么久可以把方块放到这个格子上。最左端和最右端不能放方块。

   (N<=100000,W<=1018,h[i]<=109

思路:显然是二分,对于二分的高度Mid,我们验证是否有i能够达到这个高度。我们已知需要填充的部分是从i向两旁延伸,知道左边满足i-pos>=Mid-h[pos]

右边满足pos-i>=Mid-h[pos],我们需要对于每个i找到Lpos和Rpos,然后用前缀和O(1)算出需要的方块。

现在的关键就是对于Mid,O(N)内预处理得到L和R数组:对于pos,它影响的范围是pos+Mid-h[pos]及其以后,那么记录下L[pos+Mid-h[pos]]=pos,然后扫描更新一遍最大值即可;R数组同理。

(emmm,我个zz,果然还是太弱。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=100010;
int N,L[maxn],R[maxn]; ll sum[maxn],h[maxn],W;
bool check(ll Mid)
{
    int i;
    
    for(i=1;i<=N+1;i++) L[i]=0,R[i]=N+1;
    for(i=1;i<=N;i++) if(i+Mid-h[i]<=N&&i+Mid-h[i]>=i) L[i+Mid-h[i]]=i;
    for(i=N;i>=1;i--) if(i-Mid+h[i]>=1&&i-Mid+h[i]<=i) R[i-Mid+h[i]]=i; //方向不能反,因为要最近的 
    for(i=1;i<=N;i++) L[i]=max(L[i],L[i-1]);
    for(i=N;i>=1;i--) R[i]=min(R[i],R[i+1]);
    for(i=1;i<=N;i++){
        if(R[i]==N+1||L[i]==0) continue;
        ll res=0;
        res+=1LL*(Mid+Mid-(i-L[i])+1)*(i-L[i])/2;
        res+=1LL*(Mid-1+Mid-1-(R[i]-i-1)+1)*(R[i]-i-1)/2;
        res-=sum[R[i]-1]-sum[L[i]];
        if(res<=W) return true;
    }
    return false;
}
int main()
{
    scanf("%d%I64d",&N,&W);
    ll l=0,r=2000000000,Mid,ans;
    for(int i=1;i<=N;i++) scanf("%I64d",&h[i]),l=max(l,h[i]),sum[i]=sum[i-1]+h[i];
    while(l<=r){
        Mid=(l+r)/2;
        if(check(Mid)) l=Mid+1,ans=Mid;
        else r=Mid-1;
    }
    printf("%I64d\n",ans);
    return 0; 
}

 

posted @ 2018-08-13 20:56  nimphy  阅读(473)  评论(0编辑  收藏  举报