1. 程式人生 > >hdu~3530(單調佇列)

hdu~3530(單調佇列)

單調佇列就是佇列中的元素是單調遞增或遞減的。比如把 5 2 3 1 4 入隊:

減:、、、、、、、、、、、增:

5 、、、、、、、、、、、、5

5 2 、、、、、、、、、、、2 

5 3 、、、、、、、、、、、2 3

5 3 1、、、、、、、、 、、1

5 4 、、、、、、、、、、、1 4

這個還是好理解的,但是,我們得會用單調佇列這一特性去解決題目,抽象出題目中有類似的操作。

題意:

給三個數   n,x,y;

接下來n個數num[1~n];

求滿足這個條件的最長區間長度:區間內最大值與最小值之差在 x~y之間。

方法:

單調佇列記錄下標。

由一個遞增,一個遞減的單調佇列,可得前面的某個位置~當前位置

的最大差值def=num[q1.front()]-num[q2.front()];

如果def>y,則讓下標靠前的那個出佇列。

上程式碼,看註釋:

#include <stdio.h>
#include <iostream>
#include <deque>

using namespace std;

inline int  fmax(int a,int b){return a>b?a:b;}  

int main()
{
    int n,x,y;
    int num[100005];
    while(scanf("%d %d %d",&n,&x,&y)!=EOF)
    {
        for(int i=1;i<=n;++i)
            scanf("%d",&num[i]);
        deque<int >q1,q2;   //兩個佇列,q1.front()存最大值,q2.front()存最小值
        int max=0,last=0;   //last記錄最後彈出元素的位置
        for(int i=1;i<=n;i++){
            while(!q1.empty() && num[i]>num[q1.back()]) q1.pop_back();//維護佇列單調型
            while(!q2.empty() && num[i]<num[q2.back()]) q2.pop_back();
            q1.push_back(i);
            q2.push_back(i);
        //若對不空,且def>y,讓下標靠前的出隊。
            while(!q1.empty() && !q2.empty() && num[q1.front()]-num[q2.front()]>y){
                if(q1.front()>q2.front())
                {
                    last=q2.front();
                    q2.pop_front();
                }
                else if(q1.front()<q2.front())
                {
                    last=q1.front();
                    q1.pop_front();
                }
                else if(q1.front()>q2.front())
                {
                    last=q2.front();
                    q1.pop_front();
                    q2.pop_front();
                }
            }
        
            if(!q1.empty() && !q1.empty() && num[q1.front()]-num[q2.front()]>=x)
                max=fmax(max,i-last);//若當前區間的def滿足>=x,取區間最大長度
        }
        printf("%d\n",max);
    }

    return 0;
}