HDU 3530Subsequence(单调队列维护)

来源:互联网 发布:21天学通java txt 编辑:程序博客网 时间:2024/06/05 00:56

题意:给n个数的序列,子序列(连续的,题意描述得不是很清楚),要求它的子序列  m<=最大值(Max)-最小值(Min)<=k   (n<=10^5)

分析:和这道题类似POJ 2823Sliding Window分析题意可知,其实就是求一个区间它的最值满足该条件,且该区间最长,则用两个单调队列维护此时序列的最大值q1和最小值q2。

现态假设  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 1000000000int 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;}

0 0
原创粉丝点击