单调队列总结

单调队列

就是保持队列中的元素始终保持单调性,这个数据结构就是单调队列

它的作用就是维护最值、求第一个比i小(大)的数的下标等等

还有个单调栈来着,不过我们可以用一个双端队列就足够了

如果要维护最大值,就用单调递减队列,反之,用递增队列

1、hdu3530 Subsequence 单调队列入门题

这题求的是最大值减去最小值不小于m不大于k的最长长度

这题用单调队列维护最大值和最小值即可

#include<iostream>
using namespace std;
#define MAX 1000005
int a[MAX],deq1[MAX],deq2[MAX];
int Min[MAX],Max[MAX];
int n,m,k;
int main()
{
    while(cin>>n>>m>>k){
    for(int i=1;i<=n;i++)
        cin>>a[i];
    int head1=0,tail1=0;
    int head2=0,tail2=0;
    int ans=0;
    int now=1;
    for(int i=1;i<=n;i++)
    {
        while(head1<tail1&&a[deq1[tail1-1]]<a[i]) tail1--;
        while(head2<tail2&&a[deq2[tail2-1]]>a[i]) tail2--;
        deq1[tail1++]=i;
        deq2[tail2++]=i;
        //cout<<head1<<head2<<endl;
           while(head1<tail1&&head2<tail2&&a[deq1[head1]]-a[deq2[head2]]>k)
            {
                if(deq1[head1]<deq2[head2])now=deq1[head1++]+1;
                else now=deq2[head2++]+1;
            }
            if(head1<tail1&&head2<tail2&&a[deq1[head1]]-a[deq2[head2]]>=m)
            {
                if(ans<i-now+1)ans=i-now+1;
            }
    }
    cout<<ans<<endl;
    }
}

hdu3530

2、poj2559 Largest Rectangle in a Histogram

求包含的最大面积,维护两个单调队列,队列求第一个比i大(小)的数

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define MAX 1000005
int deq[MAX];
long long L[MAX],R[MAX];
long long h[MAX];
int n;
int main()
{
    while(~scanf("%d",&n)){
        if(n==0) break;
    memset(h,-1,sizeof(h));
    for(int i=1;i<=n;i++)
        scanf("%lld",&h[i]);
    memset(deq,0,sizeof(deq));
    int head=0,tail=0;
    deq[tail++]=0;
    for(int i=1;i<=n;i++)
    {
        while(head<tail&&h[deq[tail-1]]>=h[i])tail--;
         L[i]=deq[tail-1]+1;
        deq[tail++]=i;
    }
    memset(deq,0,sizeof(deq));
    deq[tail++]=n+1;
    for(int i=n;i>0;i--)
    {
        while(head<tail&&h[deq[tail-1]]>=h[i])tail--;
        R[i]=deq[tail-1]-1;
        deq[tail++]=i;
    }
    long long res=0;
    for(int i=1;i<=n;i++)
    {
        res=max(res,h[i]*(R[i]-L[i]+1));
    }
    printf("%lld\n",res);
    }
}

poj2559

3、poj2823 Sliding Window

维护两个单调队列求最大和最小值即可

#include<iostream>
#include<stdio.h>
using namespace std;
#define MAX 1000000
int n,k;
int deq1[MAX],deq2[MAX];
int Max[MAX],Min[MAX];
int a[MAX];
int main()
{
    while(~scanf("%d %d",&n,&k))
    {
        int head1=0,tail1=0;
        int head2=0,tail2=0;
        for(int i=1;i<=n;i++)
         {
                scanf("%d",&a[i]);
                while(head1<tail1&&a[deq1[tail1-1]]<a[i]) tail1--;
                while(head2<tail2&&a[deq2[tail2-1]]>a[i]) tail2--;
                deq1[tail1++]=i;
                deq2[tail2++]=i;
                while(head1<tail1&&i-deq1[head1]>=k) head1++;
                while(head2<tail2&&i-deq2[head2]>=k) head2++;
                Max[i]=a[deq1[head1]];
                Min[i]=a[deq2[head2]];
         }
         for(int i=k;i<=n;i++){
             printf("%d ",Min[i]);
         }
         putchar(‘\n‘);
         for(int i=k;i<=n;i++){
            printf("%d ",Max[i]);
         }
         putchar(‘\n‘);
    }
}

poj2559

4、poj3017 Cut the Sequence

题意是求把数列分成几块后每块的最大值的最小值,注意每块的和不超过M

题解:dp[i]表示分块后的最小值

则dp[i]=min{dp[i],dp[j]+max(a{j+1,i} }

这个dp可以用单调队列优化,维护一个单调递减队列,然后遍历队列里的值

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
typedef long long ll;
#define MAX 100005
int n;
ll m;
ll a[MAX];
ll dp[MAX];
struct node
{
    int index;
    ll val;
}deq[MAX];
int main()
{
    while(~scanf("%d %lld",&n,&m)){
    bool flag=false;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        if(a[i]>m)
          flag=true;
    }
    if(flag)
    {
        printf("-1\n");
       continue;
    }
    else
    {
        int head=0,tail=0;
        int pos=1;
        ll sum=a[1];
        deq[tail].val=dp[1]=a[1];
        deq[tail++].index=1;
        for(int i=2;i<=n;i++)
        {
            sum+=a[i];
            while(sum>m&&pos<i)
                sum-=a[pos],pos++;
            while(head<tail&&deq[tail-1].val<=a[i]) tail--;
            deq[tail].val=a[i];deq[tail++].index=i;
            while(head<tail&&deq[head].index<pos)
                head++;
            dp[i]=dp[pos-1]+deq[head].val;
            for(int j=head;j<tail-1;j++)
                dp[i]=min(dp[i],dp[deq[j].index]+deq[j+1].val);
        }
        printf("%lld\n",dp[n]);
    }
}
}

poj3017

原文地址:https://www.cnblogs.com/zhgyki/p/9563338.html

时间: 2024-10-05 10:29:08

单调队列总结的相关文章

【动态规划】【单调队列】tyvj1305 最大子序和

http://blog.csdn.net/oiljt12138/article/details/51174560 单调队列优化dp #include<cstdio> #include<deque> #include<algorithm> #include<iostream> using namespace std; typedef long long ll; int n,m; ll a[300100],ans; deque<int>q; int

hdu_5884_Sort(二分+单调队列)

题目链接:hdu_5884_Sort 题意: 有n个数,每个数有个值,现在你可以选择每次K个数合并,合并的消耗为这K个数的权值和,问在合并为只有1个数的时候,总消耗不超过T的情况下,最小的K是多少 题解: 首先要选满足条件的最小K,肯定会想到二分. 然后是如何来写这个check函数的问题 我们要贪心做到使消耗最小,首先我们将所有的数排序 然后对于每次的check的mid都取最小的mid个数来合并,然后把新产生的数扔进优先队列,直到最后只剩一个数. 不过这样的做法是n*(logn)2 ,常数写的小

[Vijos 1243]生产产品(单调队列优化Dp)

Description 在经过一段时间的经营后,dd_engi的OI商店不满足于从别的供货商那里购买产品放上货架,而要开始自己生产产品了!产品的生产需要M个步骤,每一个步骤都可以在N台机器中的任何一台完成,但生产的步骤必须严格按顺序执行.由于这N台机器的性能不同,它们完成每一个步骤的所需时间也不同.机器i完成第j个步骤的时间为T[i,j].把半成品从一台机器上搬到另一台机器上也需要一定的时间K.同时,为了保证安全和产品的质量,每台机器最多只能连续完成产品的L个步骤.也就是说,如果有一台机器连续完

单调队列

先放上luogu的题目链接--滑稽窗口 然后我们再来讲单调队列 单调队列是指这样一种队列:在队列中的元素为单调递增状态或单调递减状态. 例如1 2 3 4 5和9 2 1都是单调队列,但1 2 2 3 4和4 3 4 5就不是单调队列. 但普通队列明显是维持不了单调队列的性质的. 为了维持单调队列的单调性质,我们只好想一些方法.方法就是修改队列的性质.单调队列不仅队头可以出队,队尾也可以出队. 比如说有一个单调队列是 1 3 7 8 现在突然要从队尾进来一个6如果单纯的把6插进队尾的话,那这个队

单调队列 BZOJ 2096 [Poi2010]Pilots

2096: [Poi2010]Pilots Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 819  Solved: 418[Submit][Status][Discuss] Description Tz又耍畸形了!!他要当飞行员,他拿到了一个飞行员测试难度序列,他设定了一个难度差的最大值,在序列中他想找到一个最长的子串,任意两个难度差不会超过他设定的最大值.耍畸形一个人是不行的,于是他找到了你. Input 输入:第一行两个有空格隔开的整数k(0

HDU 3706 Second My Problem First (单调队列)

题意:求给定的一个序列中最长子序列,该子序列的最大值和最小值介于m和k之间. 析:用两个单调队列来维护一个最小值,一个最大值,然后每次更新即可. 代码如下; #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <i

codevs3327选择数字(单调队列优化)

3327 选择数字 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 给定一行n个非负整数a[1]..a[n].现在你可以选择其中若干个数,但不能有超过k个连续的数字被选择.你的任务是使得选出的数字的和最大. 输入描述 Input Description 第一行两个整数n,k 以下n行,每行一个整数表示a[i]. 输出描述 Output Description 输出一个值表示答案. 样例输入 Sample Input 5 2

【NOIP数据结构专项】单调队列单调栈

[洛谷P1901 ]发射站 http://www.luogu.org/problem/show?pid=1901 题目描述 某地有 N 个能量发射站排成一行,每个发射站 i 都有不相同的高度 Hi,并能向两边(当 然两端的只能向一边)同时发射能量值为 Vi 的能量,并且发出的能量只被两边最近的且比 它高的发射站接收. 显然,每个发射站发来的能量有可能被 0 或 1 或 2 个其他发射站所接受,特别是为了安 全,每个发射站接收到的能量总和是我们很关心的问题.由于数据很多,现只需要你帮忙计 算出接收

【单调队列优化DP】BZOJ1855-[Scoi2010]股票交易

[题目大意] 已知第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每个i,都有APi>=BPi),第i天的一次买入至多只能购买ASi股,一次卖出至多只能卖出BSi股. 股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔W天,也就是说如果在第i天发生了交易,那么从第i+1天到第i+W天,均不能发生交易.同时,在任何时间,一个人的手里的股票数不能超过MaxP. 在第1天之前,有一大笔钱(可以认为钱的数目无限),没有任何股票,求T天之后最多赚到多

转: 单调队列

我们从最简单的问题开始: 给定一个长度为N的整数数列a(i),i=0,1,...,N-1和窗长度k. 要求: f(i) = max{a(i-k+1),a(i-k+2),..., a(i)},i = 0,1,...,N-1 问题的另一种描述就是用一个长度为k的窗在整数数列上移动,求窗里面所包含的数的最大值. 解法一: 很直观的一种解法,那就是从数列的开头,将窗放上去,然后找到这最开始的k个数的最大值,然后窗最后移一个单元,继续找到k个数中的最大值. 这种方法每求一个f(i),都要进行k-1次的比较