• [Luogu P1886]滑动窗口--单调队列入门


    题目描述

    现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。

    例如:

    The array is [1 3 -1 -3 5 3 6 7], and k = 3.

    输入输出格式

    输入格式:

    输入一共有两行,第一行为n,k。

    第二行为n个数(<INT_MAX).

    输出格式:

    输出共两行,第一行为每次窗口滑动的最小值

    第二行为每次窗口滑动的最大值

    这题是单调队列入门题。题意清晰明了,求区间最大(小)。第一反应是线段树或者RMQ,但是数据范围爆炸。这道题和普通的区间的区别就在于它的区间长度是固定的。所以使用时间复杂度为O(n)的单调队列来解决。

    什么是单调队列呢?单调队列是一种特殊的双端队列,其内部具有单调性(有点像优先序列,但有着本质区别)。

    如何实现插入?从队尾插入,若破坏了单调性,则删除队尾元素(这个删除决定了什么题能用什么题不能用),直到找到一个不影响的位置。

    如何实现输出?访问队首(真是方便)

    如何解决这道题?首先设一个区间为(l,r),则有max(l+1,r+1)=max(a[r+1],max(a[l+1],a[l+2]...a[r])),那么max(l+1,r+1)与max(l,r)其实是有很大一部分重叠的,那么在问题实现的时候就只需要先删除单调队列中不在区间里的数(a[l]),再插入新数(a[r+1]),剩余的不变,就可以解决了。

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 using namespace std;
     5 inline int read(){
     6     int res=0,f=1;
     7     char ch=getchar();
     8     while(ch<'0'||ch>'9'){
     9         if(ch=='-')f=-1;
    10         ch=getchar();
    11     }
    12     while(ch>='0'&&ch<='9'){
    13         res=res*10+(ch-'0');
    14         ch=getchar();
    15     }
    16     return res*f;
    17 }
    18 const int N=1e6+5;
    19 int nsf[N],nbf[N],que[N],number[N],a[N];
    20 int n,k,head,tail;
    21 inline void INT(){
    22     n=read();k=read();
    23     for(int i=1;i<=n;++i)a[i]=read();
    24 }
    25 inline void findmin(){
    26     head=1;tail=0;//队头、尾初始化 
    27     for(int i=1;i<=n;++i){//插入a[i]到单调序列 
    28         while(number[head]<i-k+1&&head<=tail)++head;
    29         //从队首开始找,“过时”的删除 
    30         while(a[i]<=que[tail]&&head<=tail)--tail;
    31         //插入时从队尾插入,维护单调上升性质 
    32         number[++tail]=i;que[tail]=a[i];
    33         //number保存插入时的“时间戳”,que表示值 
    34         nsf[i]=que[head];//当前队列中最小值 
    35     }
    36 }
    37 inline void findmax(){
    38     head=1;tail=0;
    39     for(int i=1;i<=n;++i){
    40         while(number[head]<i-k+1&&head<=tail)++head;
    41         while(a[i]>=que[tail]&&head<=tail)--tail;
    42         number[++tail]=i;que[tail]=a[i];
    43         nbf[i]=que[head];
    44     }
    45 }
    46 int main(){
    47 INT();//输入 
    48 findmin();//动态规划求单调队列最小值 
    49 findmax();
    50 for(int i=k;i<=n;++i)printf("%d ",nsf[i]);
    51 cout<<endl;
    52 for(int i=k;i<=n;++i)printf("%d ",nbf[i]);
    53 return 0;
    54 }

    第一次写随笔还有点小兴奋呢~

  • 相关阅读:
    C# Tostring()方法
    sql order by和case THEN 并用
    Lazarus Reading XML- with TXMLDocument and TXPathVariable
    Lazarus Reading XML- with TXMLDocument and TDOMNode
    Lazarus Coolbar and AnchroDocking
    Windows live writer 2012 测试
    组态王数据字典区块定义
    组态软件状态指示定义
    西门子Step7中DB块结构导出
    Delphi 不用标题栏移动窗体
  • 原文地址:https://www.cnblogs.com/clockwhite/p/10540868.html
Copyright © 2020-2023  润新知