BZOJ 4385 Wilcze doły - 单调队列

本文介绍了一种基于双指针思想的O(n)算法实现,该算法利用单调队列维护区间最大值,解决特定数值覆盖问题。通过左右指针确定数值区间,并确保区间和不超过预设限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看到这个数据规模,大概只能是O(n)了,选择一段忽略,很明显应该是选择一段内的最大值,考虑到单调队列。


这道题需要用到双指针的思想。通过left和right两个指针固定一段数,其中被覆盖的肯定是最大的一段m,通过单调队列维护覆盖掉那一段的最大值。每次right右移需要保证left要取到最大,于是加上right节点后判断 区间和 - 单调队列维护的最大值 是否大于p,若超出p左移left指针。保证left取到最小值,即满足小于等于p即停下,记录区间长度然后继续左移left。

这里单调队列的维护肯定以每次新加入的right为准,然后发现维护的一段m的左端点已不在[left,right]区间内,则直接舍弃。由于以left作为判定条件,所以left右移时需要维护单调队列,这个一定要记住。


#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>

using namespace std;

const int maxn=2000005;

int n,ans,m;
int a[maxn],q[maxn];
long long limit,sum[maxn];

long long read()
{
	long long x=0;char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
	return x;
}
int main()
{
	n=read();limit=read();m=read();
	for(int i=1;i<=n;i++)
		a[i]=read(),sum[i]=1LL*a[i]+sum[i-1];
	int right=1,left=1,head=1,rear=0;
	long long temp=a[1];
	q[++rear]=1;
	while(right<=n)
	{
		while(true)
		{
			while(head<=rear&&right>m&&q[head]-m+1<left)head++;
			if(right>m&&temp-sum[q[head]]+sum[q[head]-m]>limit)
				temp-=a[left++];
			else break;
		}
		ans=max(ans,right-left+1);
		temp+=a[++right];
		while(head<=rear&&sum[right]-sum[right-m]>sum[q[rear]]-sum[q[rear]-m])
			rear--;
		q[++rear]=right;
	}
	printf("%d",ans);
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值