• 滑动窗口 单调队列


    本人水平有限,题解不到为处,请多多谅解

     本蒟蒻谢谢大家观看

    题目:传送门

    很明显求最值问题,还带区间,用单调队列来维护保证时间复杂度在O(N),每个元素出队进队各一次,所以在O(1)内即可完成。

    1:维护队首(就是如果你已经是当前的m个之前那你就可以被删了,head++)

    2:在队尾插入(每插入一个就要从队尾开始往前去除冗杂状态)

    我们要维护两个单调队列,一个递增,一个递减。

    递增单调队列:

    其中num表示枚举到的位置,num[head]表示头结点所在的位置,因为此时i表示当前枚举的位置,k表示需要的个数,所以num[head]<i-k+1为头结点所在的位置,当且仅当head<=tail时,头结点才会扩展,表示队内有元素

    a[i]表示当前位置上的值,q[tail]表示单调队列中末尾的值,如果a[i]<q[tail]表示当前的值小于队列末端的值,因为我们首先维护的是单调递增队列,

    只要队列里有元素,并且尾元素比待处理值大,即表示尾元素已经不可能继续在队内,所以出队。直到尾元素小于待处理值(队首肯定最小,依次递增),满足"单调"递增。将尾部元素不断插入至队列中,直到第一个入队的尾部元素成了头结点时,保证q[head]为最小值

    递减单调队列

    同理可得:a[i]>q[tail]表示当前值大于队内末端元素值,因为我们维护的是单调递减队列

    只要队列里有元素,并且尾元素比待处理值小,即表示尾元素已经不可能继续在队内,所以出队。直到尾元素大于待处理值(队首肯定最大,依次递减),满足"单调"递减。将尾部元素不断插入至队列中,直到第一个入队的尾部元素成了头结点时,保证q[head]为最大值

    code:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int n,k,Fmax[1000010],num[1000010],q[1000010],Fmin[1000010];
     4 int a[1000010];
     5 int head,tail;
     6 void dmin()
     7 {
     8     head=1;
     9     tail=0;
    10     for(int i=1;i<=n;i++)
    11     {
    12         while(num[head]<i-k+1&&head<=tail)head++;
    13         while(a[i]<q[tail]&&head<=tail)tail--;
    14         num[++tail]=i;
    15         q[tail]=a[i];
    16         Fmin[i]=q[head];
    17     }
    18 }
    19 void dmax()
    20 {
    21     head=1;
    22     tail=0;
    23     for(int i=1;i<=n;i++)
    24     {
    25         while(num[head]<i-k+1&&head<=tail)head++;
    26         while(a[i]>q[tail]&&head<=tail)tail--;
    27         num[++tail]=i;
    28         q[tail]=a[i];
    29         Fmax[i]=q[head];
    30     //    cout<<"i-k+1= "<<i-k+1<<endl;
    31     //    cout<<"i= "<<i<<endl;
    32     //    cout<<"num[head]= "<<num[head]<<endl;
    33     //    cout<<"head= "<<head<<endl;
    34     //    cout<<"tail= "<<tail<<endl;
    35     //    cout<<"num[++tail]= "<<num[++tail]<<endl;
    36     //    cout<<"q[tail]= "<<q[tail]<<endl;
    37     //    cout<<"q[head]= "<<q[head]<<endl;
    38     }
    39 }
    40 int main()
    41 {
    42     cin>>n>>k;
    43     for(int i=1;i<=n;i++)
    44     cin>>a[i];
    45     dmin();
    46     dmax();
    47     for(int i=k;i<n;i++)
    48     cout<<Fmin[i]<<" ";
    49     cout<<Fmin[n]<<endl;
    50     for(int i=k;i<n;i++)
    51     cout<<Fmax[i]<<" ";
    52     cout<<Fmax[n]<<endl;
    53     return 0;
    54 }
  • 相关阅读:
    ural 1519 fomular 1 既插头DP学习笔记
    2016集训测试赛(十九)Problem C: 无聊的字符串
    2016集训测试赛(十九)Problem A: 24点大师
    2016集训测试赛(二十)Problem B: 字典树
    写一个addEventListener以及removeEventListener
    关于props的注意事项!
    swiper轮播始终居中active图片
    vue中登录模块的插件封装
    v-show
    v-if
  • 原文地址:https://www.cnblogs.com/nlyzl/p/11683518.html
Copyright © 2020-2023  润新知