HDU 3530 Subsequence

来源:互联网 发布:布艺沙发床价格淘宝 编辑:程序博客网 时间:2024/06/06 12:55

HDU 3530 Subsequence

单调队列学习:

应用更新区间内最大值(最小值)

队列中存储的元素是严格递减的(存储最大值时)

举一个例子:n=9,k=3;(k是指区间长度为k时)

7 5 3  1 9 8 4 6 2

队列的插入和删除何时进行

i=1    时    { (7,1)}    //存储的每个元子是(数值,脚标)

i=2    时    { (7,1),(5,2)}

i=3    时    { (7,1),(5,2),(3,3)}  //插入元素比队尾元素小,直接插入队尾

i=4    时    { (5,2),(3,3),(1,4)}  //当差入队尾后,队列维护的脚标范围大于k删除队首元子直至小于等于k

i=5    时    { (9,5)}      //当插入元子数值大于队尾元素删除队尾,直至队尾大于插入元子数值or队列为空为止

i=6    时    { (9,5),(8,6)}

i=7    时    { (9,5),(8,6),(4,7)}

i=8    时    { (8,6),(6,8)}

i=9    时    { (6,8),(2,9)}

所以任意时刻队首元素都是区间最大值

/**HDU 3530 Subsequence单调队列学习:题意:在一个序列中找到最长的连续序列max-min大于等于m小于等于k的长度用单调队列,存储一段区间的最大值和最小值尽量让队列处理范围最大(满足约定条件下的)*/#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#define maxn 100005using namespace std;int a[maxn];int q1[maxn],q2[maxn];      //两个单调队列,分别存储最大值和最小值int head1,head2,rear1,rear2;//两个队列的头尾节点int main(){    int n,m,k;    while(~scanf("%d%d%d",&n,&m,&k)){        int minl=1,ans=0;        head1=head2=rear1=rear2=1;        for(int i=1;i<=n;i++){            scanf("%d",&a[i]);            while(head1<rear1&&a[q1[rear1-1]]<a[i]) rear1--;            while(head2<rear2&&a[q2[rear2-1]]>a[i]) rear2--;            q1[rear1++]=i;            q2[rear2++]=i;            //找到最小的队列左边侧,且满足区间最大值和区间最小值之差小于等于k            while(head1<rear1&&head2<rear2&&a[q1[head1]]-a[q2[head2]]>k){                if(q1[head1]<q2[head2]) minl=q1[head1++]+1;                else minl=q2[head2++]+1;            }            //如果满足区间最大值和区间最小值之差大于等于m,更新结果            if(head1<rear1&&head2<rear2&&a[q1[head1]]-a[q2[head2]]>=m)                ans=max(ans,i-minl+1);        }        printf("%d\n",ans);    }    return 0;}


0 0
原创粉丝点击