[BZOJ 2086]Poi 2010 Blocks

实战的时候逗比的使劲儿优化O(mnlgn)的算法,搞得吐血后才多对1个点,还是有2个点毫无压力的T啦敲打

然后看了题解才发现自己逗比到一定境界了。。。。

我们的目的就是找到最小的j,使得j<i且s[j]<s[i]。只分析到这是不够的,因为我们不是要求每一个i对应的j,只要求出最大的j-i。

这样我们就可以去掉lgn了。把s最成一个单调下降的序列,现在队列求出n对应的j(很明显j存在于这个下降序列中),我们发现在找n-1对应的j中,若想更新答案,其对应的j必定比n对应的j小!

因此我们只用两个指针不停地移动就行了。复杂度O(nm)

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
const int Maxn=1000005;
int n,m,i,j,ans,l,r,mid,t,k,a[Maxn],q[Maxn];
LL s[Maxn];

int read(){
  char ch=getchar();
  int ret=0;
  while (ch<'0'||ch>'9')ch=getchar();
  while (ch>='0'&&ch<='9')
    {ret=ret*10+ch-'0';ch=getchar();}
  return ret;
}

int main(){
  n=read(); m=read();
  for (i=1;i<=n;i++)
    a[i]=read();
  while (m--){
  	k=read();
    for (i=1,ans=0,t=0;i<=n;i++){
  	  s[i]=s[i-1]+(LL)a[i]-k;
  	  if (s[q[t]]>s[i]) q[++t]=i;
    }
    for (i=n,j=t;j>=0&&i>=0;i--){
      while (j>=0 &&  s[i]>=s[q[j]]) j--;
      j++;
      ans=max(ans,i-q[j]);
    }
    printf("%d",ans);
    if (m) printf(" "); else printf("\n");
  }
  return 0;
}


你可能感兴趣的:(poi,2010,单调队列)