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;
}

猜你喜欢

转载自www.cnblogs.com/mysh/p/11826222.html