P3512 [POI2010]PIL-Pilots

题目

给定n,k和一个长度为n的序列,求最长的最大值最小值相差不超过k的序列

分析

可以直接双指针+RMQ来维护,复杂度是 \(O(nlogn)\) 的(约束RMQ爬)。

这里讲一个单调队列的思路。

维护两个单调队列,一个单调上升,一个单调下降。

然后每加入一个元素先更新两个队列,然后看一下两个队首的差是否大于 \(k\) ,是的话就弹出两者编号更小的那一个(这里就类似双指针的移动左端点了)

然后更新答案就是弹出的那一个位置到当前这个位置(没弹出那更好,直接继承上一个答案)。

代码

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;char ch=getchar();bool f=false;
	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
	while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
#define int long long
const int N=3e6+5,INF=1e9+7;
int n,m;
int a[N],que1[N],hh1=1,tt1,que2[N],hh2=1,tt2;
inline void cmax(int &x,int y){if(y>x) x=y;}
signed main(){
	read(m),read(n);int Ans=0,tmp=1;
	for(int i=1;i<=n;i++) read(a[i]);
	hh1=tt1=hh2=tt2=que1[1]=que2[1]=1;
	for(int i=2;i<=n;i++){
		while(hh1<=tt1&&a[i]>a[que1[tt1]]) tt1--;
		while(hh2<=tt2&&a[i]<a[que2[tt2]]) tt2--;
		que1[++tt1]=i,que2[++tt2]=i;
		while(a[que1[hh1]]-a[que2[hh2]]>m&&hh1<=tt1&&hh2<=tt2){
			if(que2[hh2]<que1[hh1]) hh2++,tmp=que2[hh2-1]+1;
			else hh1++,tmp=que1[hh1-1]+1;
		} 
		cmax(Ans,i-tmp+1);
	}
	write(Ans);
	return 0;
}

总结

这道题的坑点:输入和描述的\(n,k\)是反着来的..

posted @ 2021-06-25 20:34  __Anchor  阅读(52)  评论(0编辑  收藏  举报