BZOJ4123 : [Baltic2015]Hacker

黑掉的一定是一个长度为$\lfloor\frac{n+1}{2}\rfloor$的区间。

于是枚举初始点,然后查询包含它的区间的最小值。

通过维护前后缀最小值+单调队列$O(n)$解决。

 

#include<cstdio>

#define N 500010

int n,k,i,a[N<<1],s[N],pre[N],suf[N],q[N],h,t,ans;

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 void max(int b){if(ans<b)ans=b;}

inline int min(int a,int b){return a<b?a:b;}

int main(){

  read(n);k=(n+1)/2-1;

  for(i=1;i<=n;i++)read(a[i]),a[i+n]=a[i];

  for(i=2;i<=n*2;i++)a[i]+=a[i-1];

  for(i=1;i<=n;i++)s[i]=a[i+k]-a[i-1];

  for(pre[0]=s[i=1];i<=n;i++)pre[i]=min(pre[i-1],s[i]);

  for(suf[n+1]=s[i=n];i;i--)suf[i]=min(suf[i+1],s[i]);

  for(h=i=1;i<=k;q[++t]=i++){

    max(min(pre[i],suf[i+n-k]));

    while(h<=t&&s[q[t]]>=s[i])t--;

  }

  for(;i<=n;i++){

    while(h<=t&&s[q[t]]>=s[i])t--;q[++t]=i;

    while(i-q[h]>k)h++;

    max(s[q[h]]);

  }

  return printf("%d",ans),0;

}

  

你可能感兴趣的:(hack)