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\)是反着来的..