1. 程式人生 > >HDU 3530 單調佇列

HDU 3530 單調佇列

題意:給n個數和m,k,問你數列中最長的子序列,其中最大值減去最小值大於等於m小於等於k

思路:想著想著想到尺取去了,寫了一半實現不了((/ □ \)),一看單調佇列也沒怎麼練過,大致就只知道單調佇列肯定是維護一個什麼東西,只能看大神們的思路了,維護了兩個佇列,一個是以當前結束所構成的遞減序列的位置,另一個是以當前結束構成的遞增序列的位置,然後每次的最大值減去最小值,如果大於k,那麼就更新兩個中的一個,應該更新位置較小的那個,這樣才能使得這個區間的長度最大,然後就這麼更新就行了  PS:這思想不好想啊

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3fll;
const int maxn=100010;
int num[maxn],Q1[maxn],Q2[maxn];
int n,m,k;
int main(){
    while(scanf("%d%d%d",&n,&m,&k)!=-1){
        for(int i=1;i<=n;i++) scanf("%d",&num[i]);
        int s1=0,e1=0,s2=0,e2=0,ans=0,pos=0;
        for(int i=1;i<=n;i++){
            while(s1<e1&&num[Q1[e1-1]]<num[i]) e1--;
            while(s2<e2&&num[Q2[e2-1]]>num[i]) e2--;
            Q1[e1++]=i;Q2[e2++]=i;
            while(s1<e1&&s2<e2&&num[Q1[s1]]-num[Q2[s2]]>k){
                if(Q1[s1]<Q2[s2]) pos=Q1[s1++];
                else pos=Q2[s2++];
            }
            if(s1<e1&&s2<e2&&num[Q1[s1]]-num[Q2[s2]]>=m) ans=max(ans,i-pos);
        }
        printf("%d\n",ans);
    }
    return 0;
}