标签:单调队列
Description
Tz又耍畸形了!!他要当飞行员,他拿到了一个飞行员测试难度序列,他设定了一个难度差的最大值,在序列中他想找到一个最长的子串,任意两个难度差不会超过他设定的最大值。耍畸形一个人是不行的,于是他找到了你。
Input
输入:第一行两个有空格隔开的整数k(0<=k<=2000,000,000),n(1<=n<=3000,000),k代表Tz设定的最大值,n代表难度序列的长度。第二行为n个由空格隔开的整数ai(1<=ai<=2000,000,000),表示难度序列。
Output
输出:最大的字串长度。
Sample Input
3 9
5 1 3 5 8 6 6 9 10
Sample Output
4
(有两个子串的长度为4: 5, 8, 6, 6 和8, 6,6, 9.最长子串的长度就是4)
分析:
这题一开始想着用一个队列乱搞,过了半小时搞不出来
看hzwer的博客才发现要维护两个单调队列
和NOIP2016D2T2蚯蚓那题很相像(用三个队列的结论题)
对于此题,考虑每个右端点,它符合题意的左端点序号一定是单调递增的
所以可以用两个单调队列来做,一个保证递增,另一个保证递减
这样我们每次选取两个队列的队头,它们之间的差值一定是最大的,如果不符合题意那么把其中位置靠前的一个队头出队,以此更新答案
Code
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #define rep(i,a,b) for(int i=a;i<=b;i++) #define dep(i,a,b) for(int i=a;i>=b;i--) #define ll long long #define mem(x,num) memset(x,num,sizeof x) #ifdef WIN32 #define LL "%I64d" #else #define LL "%lld" #endif using namespace std; inline ll read() { ll f=1,x=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int maxn=3e6+6; int l1,r1,l2,r2,ans=0,k,n,a[maxn],t,q1[maxn<<1],q2[maxn<<1]; int main() { k=read(),n=read(); rep(i,1,n)a[i]=read(); l1=l2=r1=r2=1; rep(i,1,n){ while(l1<=r1&&a[i]>=a[q1[r1]])r1--;//维护单调下降的队列 while(l2<=r2&&a[i]<=a[q2[r2]])r2--;//维护单调上升的队列 q1[++r1]=i,q2[++r2]=i; while(a[q1[l1]]-a[q2[l2]]>k) if(q1[l1]<q2[l2])t=q1[l1++]; else t=q2[l2++]; ans=max(ans,i-t); } cout<<ans<<endl; return 0; }