返回顶部

Blocks(单调栈)

题干中说每次选择一个大于k的数,还要选他左右两个数其中之一加上一,最后问你最长的每个数不小于K的子序列。

这些都是障眼法,其实就是问你最长的平均值大于或等于K的最长子序列,这样就明朗了。

接下来就是找子序列的问题,因为要求的是区间最大平均值,所以不能再以单个数的值为依据来决定进出栈情况。

那只好用前缀和了,只不过要给每个数都减去K,这样还要把部分小于0的数入栈,遍历时倒序遍历,就可以求出各段的平均值了。

一旦找到满足条件的,就可以把answer更新一下,最后输出即可(记得置零)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1000005;
#define int long long
int s[N],k,i,n,m,a[N],ma,j,ans,ansl;
stack<int>q;
void clean(){
	memset(s,0,sizeof(s));
	while(!q.empty())q.pop();
	q.push(0);
	ans=0;
}
signed main(){
	scanf("%lld%lld",&n,&m);
	for(i=1;i<=n;i++)scanf("%lld",&a[i]),ma=max(ma,a[i]);
	for(i=1;i<=m;i++){
		scanf("%lld",&k);
		clean();
		if(k>ma){
			printf("0 ");
			continue;
		}
		for(j=1;j<=n;j++)s[j]=s[j-1]+a[j]-k;
		for(j=1;j<=n;j++)
			if(s[q.top()]>s[j])q.push(j);
		for(j=n;j>=0;j--){
			while(!q.empty()&&s[q.top()]<=s[j]){
				ansl=q.top();
				q.pop();
			}
			if(s[ansl]<=s[j])ans=max(ans,abs(j-ansl));
		}
		printf("%d ",ans);
		
	}	
	return 0;
}

记得开long long!!!(

posted @ 2024-02-22 08:12  无敌の暗黑魔王  阅读(18)  评论(0编辑  收藏  举报