题目大意:给n个数,一个长度为k(k<n)的闭区间从0滑动到n,求滑动中区间的最大值序列和最小值序列。

最大值和最小值是类似的,在此以最大值为例分析。

数据结构要求:能保存最多k个元素,快速取得最大值,更新时删去“过期”元素和“不再有希望”的元素,安放新元素。

单调队列的基本概念百度百科讲得比较清楚了:http://baike.baidu.com/view/3771451.htm

我的大致思路是:

1. 每个元素存储为结构体,包含它的秩和值。维护最大长度为k的单调队列,保证所有元素的秩都在区间内,且从首到尾的元素,秩递增,值递减。

2. 读入前k个元素(不存在过期问题),安放每个元素c:从队尾开始往回找到第一个大于它的元素g,将c放到g后面,c成为新的队尾

3. 队首赋给最大值序列的第一个值。

4. 读入k~n-1的元素,每读入一个元素c:

  (1)处理队首的过期元素(每次最多只可能是队首一个元素过期,因为队列长度不超过k,且秩是单调增的)

  (2)安放c(方法同前k个元素)

  (3)将新队首赋给最大值序列的下一个值

5. 输出最大值序列

想清楚了的话,代码还是比较好写的;队列没有封装,简单地用数组+首尾指针实现:

 #include <cstdio>
#include <cstring>
using namespace std; struct Node
{
int index;
int value;
}; Node max_q[],min_q[];
int max_res[],min_res[];
int front_max,front_min;//队首指针
int back_max,back_min;//队尾指针
int n,k,c; int main()
{
//freopen("c.txt","r",stdin);
scanf("%d%d",&n,&k);
back_max=back_min=front_max=front_min=;
scanf("%d",&c);
max_q[back_max].value=c;
min_q[back_min].value=c;
max_q[back_max].index=;
min_q[back_min].index=;//用第一个元素初始化
for(int j=;j<k;j++)//前k个元素
{
scanf("%d",&c);
while(back_max>= && max_q[back_max].value<=c) back_max--;
max_q[++back_max].value=c;
max_q[back_max].index=j; while(back_min>= && min_q[back_min].value>=c) back_min--;
min_q[++back_min].value=c;
min_q[back_min].index=j; }
max_res[]=max_q[].value;//区间起始位置的最值
min_res[]=min_q[].value; for(int j=k;j<n;j++)//下标为k到n-1的元素
{
scanf("%d",&c);
if(max_q[front_max].index==j-k) front_max++;
if(min_q[front_min].index==j-k) front_min++; while(back_max>=front_max && max_q[back_max].value<=c) back_max--;
max_q[++back_max].value=c;
max_q[back_max].index=j; while(back_min>=front_min && min_q[back_min].value>=c) back_min--;
min_q[++back_min].value=c;
min_q[back_min].index=j; max_res[j-k+]=max_q[front_max].value;//每读入一个元素,更新一次区间,得到一个最值
min_res[j-k+]=min_q[front_min].value;
} for(int j=;j<n-k+;j++)
printf("%d ",min_res[j]);
printf("\n");
for(int j=;j<n-k+;j++)
printf("%d ",max_res[j]);
printf("\n");
return ;
}

OJ的结果是这样的(G++会超时,尚不明原因):

最开始没有考虑过期的问题,考虑之后担心队列不够长,需不需要写成循环的;但稍加分析会发现,front指针后移只发生在删除队首过期元素时,最多只发生n-k次,那么数组开到2n就可以了。

由于是不循环的队列,只需front和back两个指针就可完成所有需要的操作。(之前因为和一个计数变量混用,并是在边界判断时WA了很多次)

把前k个元素和之后的元素分开处理是为了考虑方便,AC了之后试图把它们合并起来然后并是又WA了。。。看来有时候不必过于追求代码的简炼,初学还是清晰更重要。

【POJ 2823 Sliding Window】 单调队列的更多相关文章

  1. POJ 2823 Sliding Window + 单调队列

    一.概念介绍 1. 双端队列 双端队列是一种线性表,是一种特殊的队列,遵守先进先出的原则.双端队列支持以下4种操作: (1)   从队首删除 (2)   从队尾删除 (3)   从队尾插入 (4)   ...

  2. poj 2823 Sliding Window (单调队列入门)

    /***************************************************************** 题目: Sliding Window(poj 2823) 链接: ...

  3. POJ 2823 Sliding Window (单调队列)

    单调队列 加了读入挂比不加更慢.... 而且这份代码要交c++ 有大神G++跑了700ms..... orzorzorz #include<iostream> #include<cs ...

  4. poj 2823 Sliding Windows (单调队列+输入输出挂)

    Sliding Window Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 73426   Accepted: 20849 ...

  5. POJ 2823 Sliding Window 题解

    POJ 2823 Sliding  Window 题解 Description An array of size n ≤ 106 is given to you. There is a sliding ...

  6. 洛谷P1886 滑动窗口(POJ.2823 Sliding Window)(区间最值)

    To 洛谷.1886 滑动窗口 To POJ.2823 Sliding Window 题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每 ...

  7. POJ 2823 Sliding Window(单调队列入门题)

      Sliding Window Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 67218   Accepted: 190 ...

  8. POJ 2823 Sliding Window 【单调队列】

    题目链接:http://poj.org/problem?id=2823 题目大意:给出一组数,一个固定大小的窗体在这个数组上滑动,要求出每次滑动该窗体内的最大值和最小值. 这就是典型的单调队列,单调队 ...

  9. 【单调队列】poj 2823 Sliding Window

    http://poj.org/problem?id=2823 [题意] 给定一个长度为n的序列,求长度为k的滑窗内的最大值和最小值 [思路] 裸的单调队列 注意用C++提交,不然会T,orz我用G++ ...

  10. 题解报告:poj 2823 Sliding Window(单调队列)

    Description An array of size n ≤ 106 is given to you. There is a sliding window of size k which is m ...

随机推荐

  1. 【Xamarin挖墙脚系列:常用的Mac 命令】

    通俗点说Mac 跟Linux的爹都是Unix,他们都加入了标准的Shell命令工具,bash 所以俩系统中的命令基本通用 Linux下的操作手册,本人自己整理了一份.呵呵~~~~ 还可以使用客户端远程 ...

  2. 《how to design programs》第11章自然数

    这章让我明白了原来自然数的定义本来就是个递归的过程. 我们通常用枚举的方式引出自然数的定义:0,1,2,3,等等(etc).最后的等等是什么意思?唯一能把等等从描述自然数的枚举方法中去除的方法是自引用 ...

  3. arm linux中添加开机启动

    微处理器:S5PV210操作系统:linux3.0.8 前言:    在产品中,基本上都要屏蔽arm开发板中linux系统的对外通信,只应该通过产品的相关APP做相关操作.    因此需要把该APP添 ...

  4. 使用fdisk进行磁盘管理

    http://itercast.com/lecture/17 disk是来自IBM的老牌分区软件,几乎所有Linux系统均默认安装 fdisk是一个MBR分区工具,不可用于GPT分区 只有超级用户(r ...

  5. 【LeetCode练习题】Minimum Path Sum

    Minimum Path Sum Given a m x n grid filled with non-negative numbers, find a path from top left to b ...

  6. HTML5 Canvas Cheat Sheet

    HTML5 Canvas Cheat Sheet HTML5 Canvas Cheat Sheet v1.x

  7. hdu 4930 Fighting the Landlords--2014 Multi-University Training Contest 6

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4930 Fighting the Landlords Time Limit: 2000/1000 MS ...

  8. yum安裝的包如何保留到本地

    一, 很多时候,我们一直用yum安装的软件,但是毫无疑问,很多人都会想yum安装的软件的包存放在哪里了呢? 这是因为yum默认并不保存你所安装的包,那么如何才能保留安装的软件包呢? 方法很简单:修改y ...

  9. kafka中处理超大消息的一些考虑

    Kafka设计的初衷是迅速处理短小的消息,一般10K大小的消息吞吐性能最好(可参见LinkedIn的kafka性能测试).但有时候,我们需要处理更大的消息,比如XML文档或JSON内容,一个消息差不多 ...

  10. Sharepoint2010 通过 WebFeature 修改web.config

    using System;using System.Runtime.InteropServices;using System.Security.Permissions;using Microsoft. ...