P3503 [POI2010]KLO-Blocks
题目描述
思路
答案是一段连续的区间,而且这个区间满足平均数>=k。
将所有数减去k,则这个区间和>=0。
再求个前缀和,则s[r]>=s[l-1]。
也就是对每个s[r],我们要求满足s[l]<=s[r]的最小的l。
如果s[r]>=s[l],那么r永远不会是右边的选择,所以可以扔掉。
维护一个单调递减的栈。
查询时二分最左的<=s[r]的s[l]。
时间nlogn。
这个建栈和查询是可以分开的。
如果s[r]>=s[l],l的选择永远可以被r选择,而且会更优,所以l永远不用查询了。
所以可查询的数也可以建一个单调递减的栈。
随着s[r]递增,l是单调左移的,于是就可以O(n)了。
代码
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1000010;
int m,k,i;
int q1[N],q2[N];
int a[N],n,t1,t2;
long long sum[N],now;
int main () {
scanf("%d%d",&n,&m);
for(i=1; i<=n; i++)
scanf("%d",&a[i]);
sum[q1[0]=q2[0]=N-1]=1e18;
while(m--) {
scanf("%d",&k);
for(i=1; i<=n; i++)
sum[i]=sum[i-1]+a[i]-k;
t1=1,t2=0;
for(i=1; i<=n; i++) {
now=sum[i];
if(now<sum[q1[t1]])
q1[++t1]=i;
while(now>=sum[q2[t2]])
t2--;
q2[++t2]=i;
}
int ans=0;
for(; t2; --t2) {
now=sum[i=q2[t2]];
if(now<sum[q1[t1]])
continue;
while(now>=sum[q1[t1]])
--t1;
ans=max(ans,i-q1[t1+1]);
}
printf("%d ",ans);
}
return 0;
}

浙公网安备 33010602011771号