POJ 2823 滑动窗口 单调队列
https://vjudge.net/problem/POJ-2823
中文:https://loj.ac/problem/10175
题目
给一个长度为 $N$ 的数组,一个长为 $K$ 的滑动窗体从最左端移至最右端,你只能看到窗口中的 $K$ 个数,每次窗体向右移动一位,你的任务是找出窗体在各个位置时的最大值和最小值。
题解
滑动窗口模板题……
直接抄紫书上的话……
窗口滑动时,首先删除窗口最左边元素(如果是有用元素),然后把新元素加入单调队列。注意,比新元素大的元素都变得无用了,应当从右往左删除。
举个例子……
窗口初始状态

向右扫描

每次加入新元素到窗口就从右边删掉所有大于这个值的元素

继续……

到这里-1算有用的元素了,会删掉……

$5-2\geqslant k=3$ ,表示这个位置已经不在窗口内了……
为了存位置需要新开一个数组,既然这样干脆窗口里直接存位置就行了,比较的时候通过下标使用就好。
另外在删除的时候可以使用二分确定要删除到的位置,两个循环其实可以合并为一个。
TLE代码(其实用C++交就会AC,用G++才TLE,用快速读写优化就可以AC了)
另外这个代码是主要考虑减少时间使用去了= =显然实际应该考虑三者平衡(时间、空间、编程)……
#include<iostream>
#include<cstdio>
using namespace std;
#define REP(r,x,y) for(register int r=(x); r<(y); r++)
#define REPE(r,x,y) for(register int r=(x); r<=(y); r++)
#ifdef sahdsg
#define DBG(...) printf(__VA_ARGS__)
#else
#define DBG(...)
#endif #define MAXN 1000007 int arr[MAXN], que[MAXN], l, r;
int n,k; int main() {
#ifdef sahdsg
freopen("in.txt", "r", stdin);
#endif
scanf("%d%d", &n, &k);
REP(i,0,n) {
scanf("%d", &arr[i]);
}
l=0, r=0;
REP(i,0,k-1) {
while(l<r && arr[que[r-1]]>arr[i]) r--;
que[r++] = i;
}
bool fi = false;
REP(i,k-1,n) {
if(que[l]<=i-k) l++;
while(l<r && arr[que[r-1]]>arr[i]) r--;
que[r] = i;
if(fi) putchar(' '); else fi = true;
printf("%d", arr[que[l]]);
r++;
}
putchar('\n'); fi = false;
l=0, r=0;
REP(i,0,k-1) {
while(l<r && arr[que[r-1]]<arr[i]) r--;
que[r++] = i;
}
REP(i,k-1,n) {
if(que[l]<=i-k) l++;
while(l<r && arr[que[r-1]]<arr[i]) r--;
que[r] = i;
if(fi) putchar(' '); else fi = true;
printf("%d", arr[que[l]]);
r++;
}
return 0;
}
AC代码:
#include<iostream>
#include<cstdio>
using namespace std;
#define REP(r,x,y) for(register int r=(x); r<(y); r++)
#define REPE(r,x,y) for(register int r=(x); r<=(y); r++)
#ifdef sahdsg
#define DBG(...) printf(__VA_ARGS__)
#else
#define DBG(...)
#endif #define MAXN 1000007 int arr[MAXN], que[MAXN], l, r;
int n,k; template <class T>
inline void read(T& x) {
char c=getchar();int f=1;x=0;
while(!isdigit(c)&&c!='-')c=getchar();if(c=='-')f=-1,c=getchar();
while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=f;
}
void write(int x) {
if(x<0) {putchar('-');write(-x);return;}
if(x>9) write(x/10); putchar(x%10+'0');
} int main() {
#ifdef sahdsg
freopen("in.txt", "r", stdin);
#endif
read(n); read(k);
REP(i,0,n) {
read(arr[i]);
}
l=0, r=0;
REP(i,0,k-1) {
while(l<r && arr[que[r-1]]>arr[i]) r--;
que[r++] = i;
}
bool fi = false;
REP(i,k-1,n) {
if(que[l]<=i-k) l++;
if(l<r && arr[que[r-1]]>arr[i]) {
int fl=l, fr=r;
while(fr>fl) {
int mid=fl+((fr-fl)>>1); //[l, m) [m,r)
if(arr[que[mid]]>arr[i]) {
fr=mid;
} else {
fl=mid+1;
}
}
r=fr;
}
que[r++] = i;
if(fi) putchar(' '); else fi = true;
write(arr[que[l]]);
}
putchar('\n'); fi = false;
l=0, r=0;
REP(i,0,k-1) {
while(l<r && arr[que[r-1]]<arr[i]) r--;
que[r++] = i;
}
REP(i,k-1,n) {
if(que[l]<=i-k) l++;
if(l<r && arr[que[r-1]]<arr[i]) {
int fl=l, fr=r;
while(fr>fl) {
int mid=fl+((fr-fl)>>1); //[l, m) [m,r)
if(arr[que[mid]]<arr[i]) {
fr=mid;
} else {
fl=mid+1;
}
}
r=fr;
}
que[r++] = i;
if(fi) putchar(' '); else fi = true;
write(arr[que[l]]);
}
return 0;
}
POJ 2823 滑动窗口 单调队列的更多相关文章
- POJ 2823 滑动窗口 单调队列模板
我们从最简单的问题开始: 给定一个长度为N的整数数列a(i),i=0,1,...,N-1和窗长度k. 要求: f(i) = max{a(i-k+1),a(i-k+2),..., a(i)},i = 0 ...
- POJ 2823 Sliding Window + 单调队列
一.概念介绍 1. 双端队列 双端队列是一种线性表,是一种特殊的队列,遵守先进先出的原则.双端队列支持以下4种操作: (1) 从队首删除 (2) 从队尾删除 (3) 从队尾插入 (4) ...
- poj 2823 Sliding Window (单调队列入门)
/***************************************************************** 题目: Sliding Window(poj 2823) 链接: ...
- luoguP1886 滑动窗口 [单调队列]
题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array i ...
- [POJ2823]Sliding Window 滑动窗口(单调队列)
题意 刚学单调队列的时候做过 现在重新做一次 一个很经典的题目 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗 ...
- [洛谷P1886]滑动窗口 (单调队列)(线段树)
---恢复内容开始--- 这是很好的一道题 题目描述: 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口. 现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的 ...
- [Luogu P1886]滑动窗口--单调队列入门
题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array i ...
- POJ 2823 (滑动窗口)
这道题最容易想到的是用朴素的做法,即 每滑动一次,就遍历一次窗口找出最大最小值,这样时间复杂度为O(n*k),由于题目数据比较大,这种做法肯定是超时的. 另外,根据书上的讲解,还可以采用优先队列来求解 ...
- AcWing 154. 滑动窗口 单调队列
地址 https://www.acwing.com/problem/content/description/156/ 输入格式 输入包含两行. 第一行包含两个整数n和k,分别代表数组长度和滑动窗口的长 ...
随机推荐
- Vue2.x源码学习笔记-Vue构造函数
我们知道使用vue.js开发应用时,都是new Vue({}/*options*/) 那Vue构造函数上有哪些静态属性和方法呢?其原型上又有哪些方法呢? 一般我都会在浏览器中输入Vue来look se ...
- Ubuntu14.04安装nvidia-docker2
1.在安装nvidia-docker2以前需要先安装docker: 首先添加PPA源并更新源: add-apt-repository ppa:ubuntu-sdk-team/ppa apt-get u ...
- Gradle构建工具从入门到精通(IDEA)
1.Gradle安装 官网下载压缩包,然后解压,配置本地环境变量.主要有下面两个: GRADLE_HOME 是解压后的目录, GRADLE_USER_HOME 的作用是让其他程序检测到本地.gradl ...
- 传统前端工程使用 Vue 等框架重构的思路
这段时间遇到类似的问题,第一反应便是使用 cli 搭建项目,但是细想一下立马否决了,原因如下: 工程量太大,猴年马月能重构完,此期间原项目还是没有任何变动(如果没人跟你一起同步修改之前老项目的话 无法 ...
- Jmeter(三十七)循环控制器+交替控制器+事务控制器 完美实现接口字段参数化校验
我们在做接口自动化的时候,常常因为无法灵活的的校验接口字段而烦恼.不能自动校验接口字段的脚本,也就不能称之为接口自动化.因此,我设计了一套组合式的控制器,可以完美的解决这个问题 1:首先我们需要在本地 ...
- Vue2.0 搭建Vue脚手架(vue-cli)
介绍 Vue.js是一套构建用户界面的渐进式框架.Vue 只关注视图层,采用自底向上增量开发的设计.Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件. 阅读之前需要了解的知 ...
- net core 小坑杂记之配置文件读取 02 (控制器里读)
上次更新博客的时候提到了如何在EF的上下文里读取配置,这次介绍一下在控制器里如何读取. 先说一种简单易懂的: 首先以键值对的形式在appsettings里添加一条配置信息,接着Startup里注入配置 ...
- Python_函数的有用信息、带参数的装饰器、多个装饰器装饰一个函数
函数的有用信息 代码1: def login(username, password): """ 此函数需要用户名,密码两个参数,完成的是登录的功能. :return: T ...
- php-fpm-运行原理(转)
转载自https://studygolang.com/articles/15073 php-fpm是一种master(主)/worker(子)多进程架构,与nginx设计风格有点类似.master进程 ...
- 【学习总结】vi/vim命令是使用
每次要么想不起来用,要么进去了出不来,真是醉了.痛定思痛此处填坑. 参考教程:菜鸟教程vi/vim 实验环境:借Git-bash宝地一用 注意:记住关键的步骤! 按i a o进入输入模式(即使有时按v ...