落谷P1886(滑动窗口)

滑动窗口

在这里插入图片描述

思路

做法很多种,线段树,RMQ,单调队列。题意写的很明白,但是没有上述三种手段是无法暴力突破的,也算是单调队列的入门题了吧,单调队列的思想如下。

  1. 无论是单调递减队列还是单调递增队列头部一定是最小或者最大的。

  2. 给读入的每一个数字按顺序编号,由于每连续的K个中求最大和最小那么每次只维护前K个序列是单调队列的核心所在。一旦头部元素不在当前的连续K个范围内那么立即把头部的元素抛掉。

  3. 在维护前K个元素的时候, 以单调递减队列为例,如果当前元素的值比当前单调队列里最后一个元素要小,那么需要将队尾的元素抛出,必须严格维护该队列的单调性,否则这个队列将毫无意义。一直循环知道队列末尾的元素 小于 当前元素或者队列为空。

这道题北大也有POJ2823,但是deque会超时需要手动队列,G++也会超时,最后北大的我是用线段树过的复杂度O(nlogn)却可以过,单调队列的复杂度O(n)。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <deque>
#include <algorithm>
using namespace std;
const int maxn = 1e6+5;
struct info{
	int n,pos;
};
deque<info>dmax,dmin;
int ans[maxn];
int main()
{
	int n,k,x;
	while(~scanf("%d%d",&n,&k)){
		dmax.clear();dmin.clear();
		int cnt = 0;
		for(int i = 1;i <= n;i++){
			scanf("%d",&x);
			//头部元素超出范围需要抛掉
			if(!dmax.empty() && i - dmax.front().pos >= k)	dmax.pop_front();
			if(!dmin.empty() && i - dmin.front().pos >= k)	dmin.pop_front();
			//尾部元素小于当前元素要抛掉,维护区间最大值,下面同理
			while(!dmax.empty() && dmax.back().n < x)	dmax.pop_back();
			while(!dmin.empty() && dmin.back().n > x)	dmin.pop_back();
			info t;
			t.n = x;t.pos = i;
			dmax.push_back(t);			//尾部插入
			dmin.push_back(t);			//尾部插入
			if(i >= k){					//从第k个开始就需要输出一次,下标从1开始好理解。
				if(i != n){
					printf("%d ",dmin.front().n);
				}
				else{
					printf("%d\n",dmin.front().n);
				}
				ans[cnt++] = dmax.front().n;
			}
		}
		for(int i = 0;i < cnt-1;i++){
			printf("%d ",ans[i]);
		}
		printf("%d\n",ans[cnt-1]);
	}
	return 0;
}

愿你走出半生,归来仍是少年~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值