• BZOJ2792 : [Poi2012]Well


    二分答案mid,将差距先都调到mid以内。

    首先从左往右扫,a[i]=min(a[i],a[i-1]+mid)。

    然后从右往左扫,a[i]=min(a[i],a[i+1]+mid)。

    枚举要变为0的位置,求出L,R使得:

    a[L]>(i-L)mid

    a[R]>(R-i)mid

    此时只需要把[L,i]和[i,R]修改成一个等差数列即可满足条件且代价最小。

    注意到随着i的右移,L递增;随着i的左移,R递减,所以可以$O(n)$完成判定。

    #include<cstdio>
    #define N 1000010
    typedef long long ll;
    int n,i,j,a[N],b[N],l,r,t,mid,z,k;ll m,s[N],f[N],now;
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    inline int min(int a,int b){return a<b?a:b;}
    int check(int mid){
      for(b[1]=a[1],i=2;i<=n;i++)b[i]=min(a[i],b[i-1]+mid);
      for(i=n-1;i;i--)b[i]=min(b[i],b[i+1]+mid);
      for(now=0,i=1;i<=n;i++){
        now+=a[i]-b[i],s[i]=s[i-1]+b[i];
        if(now>m)return 0;
      }
      for(i=j=1;i<=n;i++){
        while(j<i&&b[j]<=(ll)(i-j)*mid)j++;
        f[i]=s[i-1]-s[j-1]-(ll)(1+i-j)*(i-j)*mid/2;
      }
      for(i=j=n;i;i--){
        while(j>i&&b[j]<=(ll)(j-i)*mid)j--;
        f[i]+=s[j]-s[i]-(ll)(1+j-i)*(j-i)*mid/2;
      }
      for(i=1;i<=n;i++)if(f[i]+b[i]+now<=m)return i;
      return 0;
    }
    int main(){
      read(n),scanf("%lld",&m);
      for(i=1;i<=n;i++)read(a[i]),r=r>a[i]?r:a[i];
      while(l<=r)if(t=check(mid=(l+r)>>1))r=(z=mid)-1,k=t;else l=mid+1;
      return printf("%d %d",k,z),0;
    }
    

      

  • 相关阅读:
    执行上下文和作用域,作用域链
    学习笔记一:定位
    exports和module.exports的区别——学习笔记
    伪类和伪元素
    visibility和display
    CSS选择器,层叠
    Servlet乱码处理-------续集
    Servlet的乱码处理手记
    前端框架之Semantic UI
    最完整的Oracle11g 概述
  • 原文地址:https://www.cnblogs.com/clrs97/p/4728873.html
Copyright © 2020-2023  润新知