洛谷 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 -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//第一次数组只开到十万,才有60分(不是说50分的吗)

解题思路

  一道RMQ裸题,做法很多,我用的是单调队列。单调队列跑两遍,分别求出区间最大值、区间最小值(其实不用记录答案统一输出的),边求边输出。单调队列我是看百度百科加神犇们博客上的代码看懂的,真的很好懂。

  AC以后翻看了洛谷这题5页的AC记录,外加百度一下找到的解法,总结一下RMQ有以下几种解法

  1、暴力——不说了

  2、单调队列——跑得又快,代码又短,这题AC用时在1000ms~2000ms人丑常数大。记录里普遍在1300ms到16000ms,在这范围之外的很少,我的1428ms。

  3、ST表(稀疏表,你要说是DP也行)——类似于倍增,记录一个个区间长度为1、2、4、8…的区间最值然后@#¥%,代码也挺简短我不会,正常写法$O(nlogn)$预处理(听说可以达到$O(n)$),然后$O(1)$查询(听说标准应该是$O(\log[2]{\log[2]n}),和$O(1)$差不多,就成$O(1)$了)。

  4、利用区间最值区间加性质的一系列数据结构

    a、线段树——作用大,RMQ裸题杀鸡用牛刀了,记录里普遍3000ms~7000ms(预处理真慢)。

    b、树状数组——记录里前几页没翻到,用题解里的代码测试了一下,居然才90分,一个点TLE了他的树状数组常数真大。就算这个点是1500ms吧,那总共耗时3526ms。

    c、zkw线段树——神奇的数据结构我不会,作用同样巨大,题解里的代码2410ms。

  5、最高端的做法——建一棵笛卡尔树#$%^#@,然后对每个询问在树上求一波LCA^@%%@%……好复杂我不会。

源代码

#include<stdio.h>
#include<string.h>
int a[1000010]={0},n,k;
int q[1000010]={0},l=1,r=1;

int main()
{
    scanf("%d%d",&n,&k);
    l=1,r=1;memset(q,0,sizeof(q));
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    for(int i=1;i<=n;i++)
    {
        while(l<r&&a[q[r-1]]>a[i]) r--;
        q[r++]=i;
        while(l<r&&q[l]<=i-k) l++;
        if(i>=k) printf("%d ",a[q[l]]);
    }
    printf("\n");
    l=1,r=1;memset(q,0,sizeof(q));
    for(int i=1;i<=n;i++)
    {
        while(l<r&&a[q[r-1]]<a[i]) r--;
        q[r++]=i;
        while(l<r&&q[l]<=i-k) l++;
        if(i>=k) printf("%d ",a[q[l]]);
    }
    printf("\n");
    return 0;
}
时间: 2024-10-22 19:16:53

洛谷 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 滑动窗口

P1886 滑动窗口 454通过 1.4K提交 题目提供者darkfire 标签云端↑ 难度普及+/提高 时空限制1s / 128MB 提交  讨论  题解 最新讨论更多讨论 滑动窗口 求标明空间限制 一个奇怪的问题 水印233 为什么会wa一个点,求dalao- 求大神指点 题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array is [1 3 -1 -3 5

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