洛谷P1886 滑动窗口

P1886 滑动窗口

    • 454通过
    • 1.4K提交
  • 题目提供者darkfire
  • 标签云端↑
  • 难度普及+/提高
  • 时空限制1s / 128MB

提交  讨论  题解

最新讨论更多讨论

  • 滑动窗口
  • 求标明空间限制
  • 一个奇怪的问题
  • 水印233
  • 为什么会wa一个点,求dalao…
  • 求大神指点

题目描述

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

例如:

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

输入输出格式

输入格式:

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

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

输出格式:

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

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

输入输出样例

输入样例#1:

8 3
1 3 -1 -3 5 3 6 7

输出样例#1:

-1 -3 -3 -3 3 3
3 3 5 5 6 7

说明

50%的数据,n<=10^5

100%的数据,n<=10^6

分析:这道题可以用线段树做,但是有一种更简单的方法叫做单调队列.我们可以维护一个队列,这个队列是严格递增或者严格递减的,这样当我们需要查询的时候直接输出队首元素即可,那么怎么维护呢?

假设我们要维护一个严格递增的队列,考虑元素i,如果当前队尾的元素比i大,那么i不能插入到队尾,需要向前移,直到找到一个元素j不大于i,把i置于j后面,那么i之后的元素呢?我们可以全部舍弃掉,因为维护严格递增的队列的目的是求最小值,i之后的元素已经大于i了,这样可以确保队首元素是最小值,如果一个窗口内的元素全部被删光了,那么我们直接加入元素i并且直接输出即可,要注意每次插入i的时候都要检查i的位置与队首的位置差是不是小于等于k,求得的值不能在窗口之外.   对于求最大值,类似.

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>

using namespace std;

int n, k,head,tail,a[1000010],q[1000010],num[1000010];

void getmin()
{
    for (int i = 1; i < k;i++)
    {
        while (head <= tail && i - num[head] >= k)
            head++;
        while (head <= tail && a[i] < q[tail])
            tail--;
        q[++tail] = a[i];
        num[tail] = i;
    }
    for (int i = k; i <= n; i++)
    {
        while (head <= tail && i - num[head] >= k)
            head++;
        while (head <= tail && a[i] < q[tail])
            tail--;
        q[++tail] = a[i];
        num[tail] = i;
        printf("%d ", q[head]);
    }
}

void getmax()
{
    memset(num, 0, sizeof(num));
    memset(q, 0, sizeof(q));
    for (int i = 1; i < k; i++)
    {
        while (head <= tail && i - num[head] >= k)
            head++;
        while (head <= tail && a[i] > q[tail])
            tail--;
        q[++tail] = a[i];
        num[tail] = i;
    }
    for (int i = k; i <= n; i++)
    {
        while (head <= tail && i - num[head] >= k)
            head++;
        while (head <= tail && a[i] > q[tail])
            tail--;
        q[++tail] = a[i];
        num[tail] = i;
        printf("%d ", q[head]);
    }
}

int main()
{
    scanf("%d%d", &n, &k);
    head = 1, tail = 1;
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    head = 1, tail = 1;
    getmin();
    printf("\n");
    head = 1, tail = 1;
    getmax();

    return 0;
}
时间: 2024-10-21 06:52:08

洛谷P1886 滑动窗口的相关文章

洛谷P1886 滑动窗口 单调队列

洛谷P1886 滑动窗口 单调队列 求一个固定长度的区间 最小值和最大值 单调队列求最小值时 1.刚要插入一个数 判断 其是否 小于等于 队尾的数 如果是 则将队尾的数出队 因为求的是队尾到之前的 最小值 ,所以其已经不可能成为 最小值了2.然后数字进队 3.如果队头 已经不再这个区间中,那就队头出队 最大值也是同理 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cs

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

To 洛谷.1886 滑动窗口 To POJ.2823 Sliding Window 题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array is [1 3 -1 -3 5 3 6 7], and k = 3. 输入输出格式 输入格式: 输入一共有两行,第一行为n,k. 第二行为n个数(<INT_MAX). 输出格式: 输出共两行,第一行为每次窗口滑动的最小值

洛谷 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). 输出格式: 输出共两行,第一行为每次窗口滑动的最小值 第二行为每次窗口滑动的最大值 输入输出样例 输入样例#1: 8 3 1 3 -1 -

洛谷P1886滑动窗口

题目传送门 理解题意:给定一个数列和窗口范围k,求依次向右移动窗口时每次窗口内的最大和最小值. 没什么思维难度,普及+/提高的标签纯粹是吓唬人的,一边扫过去,用两个数组maxx和minn记录每个窗口内的最大最小值,移动过程中用两个变量L和R记录窗口的左右端点,然后判断滑动窗口时最大最小值是否被移出窗口,进入窗口的值是否大于当前最大值或小于当前最小值,做完后L++,R++,用while循环控制轻松水过这题.当然,如果数据比较极端故意卡时就可能没这么轻松了.(不过我估计也不太可能会有什么题目出这么可

洛谷 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). 输出格式: 输出共两行,第一行为每次窗口滑动的最小值 第二行为每次窗口滑动的最大值 输入输出样例 输入样例#1: 8 3 1 3 -1 -

落谷P1886 滑动窗口~

很好用的线性求变换区间最值的方法,比线段树快 用到了优先队列的算法 据说能用STL双向队列解但我不会QAQ #include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> using namespace std; int n,k; int ans,l,r,a,b; int num[1000007]; int q[1000007],q

P1886 滑动窗口(单调队列)

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). 输出格式: 输出共两行,第一行为每次窗口滑动的最小值 第二行为每次窗口滑动的最大值 输入输出样例 输入样例#1: 8

P1886 滑动窗口&amp;&amp;P1440 求m区间内的最小值

单调队列入门题 P1440 求m区间内的最小值 题目描述 一个含有n项的数列(n<=2000000),求出每一项前的m个数到它这个区间内的最小值.若前面的数不足m项则从第1个数开始,若前面没有数则输出0. 输入输出格式 输入格式: 第一行两个数n,m. 第二行,n个正整数,为所给定的数列. 输出格式: n行,第i行的一个数ai,为所求序列中第i个数前m个数的最小值. 输入输出样例 输入样例#1: 复制 6 2 7 8 1 4 3 2 输出样例#1: 复制 0 7 7 1 1 3 说明 [数据规模

luogu P1886滑动窗口

\(luogu\ P1886\)滑动窗口 题目链接 这道题目比较简单,但是因为经常忘记单调队列做滑动窗口所以写博客来加深一下印象. 如果求区间最小值,我们用发现右端点从前往后扫的方法一个数如果有贡献,当且仅当当前扫描的右端点的前面到这个数中间没有比这个数更小的数,因为如果有比这个数更小的数的话,这个更小的数肯定就会成为区间的最小值.如果一个数没有贡献的时候就是区间的左端点比这个数的下标要大的时候. 所以我们用一个双端队列来维护,每次进入队列的时候检查队尾的数如果比要加入得数大的话,就不断弹出队尾