题意:给n个数的序列,子序列(连续的,题意描述得不是很清楚),要求它的子序列 m<=最大值(Max)-最小值(Min)<=k (n<=10^5)
分析:和这道题类似
POJ 2823 | Sliding Window |
现态假设 m<=q1-q2<=k
加入下列一个点:
①该点加入两个队列后会不会存在 q1-q2<m?答案是否定的,要使q1-q2<m,即使(q1-q2)减小——>q1减小或q2增大
显然这种情况是不可能的
②该点加入两个队列后不改变最大值和最小值
③该点加入两个队列后,使得q1-q2>k,即(q1-q2)增大——>q1增大或者q2减小,这种情况是可能出现的,出现后怎么办呢?显然,要减小(q1-q1),是q1出队还是q2出队?由于要求的是连续的子序列,而这个点是后加进来的,因此,出队的是id 更小的。若id出队了,则用l=id记录下出队点的下标,ans=max(ans,i-l),这里可以看出当加入的点满足条件,l的值不变,但i+1,所以长度自然加1了;
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <string.h>
#include <map>
#include <set>
using namespace std;
#define inff 1000000000
int f1,f2,r1,r2;
int a[100005];
int q1[100005],q2[100005];
void push1(int i)//dijian
{
while(f1<r1&&a[i]>a[q1[r1-1]])
{
r1--;
}
q1[r1++]=i;
}
void push2(int i)
{
while(f2<r2&&a[i]<a[q2[r2-1]])
{
r2--;
}
q2[r2++]=i;
}
int main()
{
int i,n,m,k,ans,l;
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
f1=f2=r1=r2=0;
l=0;
ans=0;
for(i=1;i<=n;i++)
{
push1(i);
push2(i);
if(a[q1[f1]]-a[q2[f2]]>k&&f1!=r1&&f2!=r2)
{
if(q1[f1]<q2[f2])
{
l=q1[f1];
f1++;
}
else
{
l=q2[f2];
f2++;
}
}
if(f1!=r1&&f2!=r2&&a[q1[f1]]-a[q2[f2]]>=m)
ans=max(ans,i-l);
}
printf("%d\n",ans);
}
return 0;
}