题解:来自http://hi.baidu.com/wzyjerry/blog/item/3838f48af40e40cafd1f1089.html
题目大意:给你一个长度为n的数组,求从左到右的每个相邻的长度为k的区间内数的最大值和最小值。
解题方法:这道题数据较大(n最大为10^6)所以用纯模拟O(n*k)是铁定挂掉的,写的好的线段树可以卡时间过去。这里我们选择更为合适的单调队列解决。STL里有类似的优先队列。单调队列就是在一个队列中保证数据的单调性,可以很方便的求制定区间极值的一种队列。每个元素只会进队一次,所以复杂度为O(n),可以有效地降低时间复杂度。下面具体地说明一下单调队列。
1.数据结构:理论上来说应当是两个数组,一个存元素,一个存这个元素在原队列中的下标。实际上如果保留原队列的话,只需要记录下标即可。这样简化为只开一个长度为n的数组Q,减少了一半的空间开销。另外要记录队首s和队尾t。
2.初始化:将队首赋值为第一个元素。
3.维护过程(这里以建立单增队列求最大值为例):依次枚举剩下的N-1个元素,并且将当前未入队的第一个元素和队尾元素比较,当且仅当队列为非空并且队尾元素的值小于当前未入队的元素时,将队尾元素删除(也就是队尾指针-1),因为当前的元素比队尾元素大,所以在区间内队尾元素不会是最大值了。重复这个过程直到队列空或者队尾元素比当前元素大,一次插入结束。
题目大意:给你一个长度为n的数组,求从左到右的每个相邻的长度为k的区间内数的最大值和最小值。
解题方法:这道题数据较大(n最大为10^6)所以用纯模拟O(n*k)是铁定挂掉的,写的好的线段树可以卡时间过去。这里我们选择更为合适的单调队列解决。STL里有类似的优先队列。单调队列就是在一个队列中保证数据的单调性,可以很方便的求制定区间极值的一种队列。每个元素只会进队一次,所以复杂度为O(n),可以有效地降低时间复杂度。下面具体地说明一下单调队列。
1.数据结构:理论上来说应当是两个数组,一个存元素,一个存这个元素在原队列中的下标。实际上如果保留原队列的话,只需要记录下标即可。这样简化为只开一个长度为n的数组Q,减少了一半的空间开销。另外要记录队首s和队尾t。
2.初始化:将队首赋值为第一个元素。
3.维护过程(这里以建立单增队列求最大值为例):依次枚举剩下的N-1个元素,并且将当前未入队的第一个元素和队尾元素比较,当且仅当队列为非空并且队尾元素的值小于当前未入队的元素时,将队尾元素删除(也就是队尾指针-1),因为当前的元素比队尾元素大,所以在区间内队尾元素不会是最大值了。重复这个过程直到队列空或者队尾元素比当前元素大,一次插入结束。
4.由于单调队列是求指定长度区间的最值,所以需要控制区间长度。当插入结束后,需要用队尾元素下标和队首元素下标计算是否在一个区间内。如果不在,队首元素出队(队首指针+1)。重复这个过程直到控制到区间内,一次最大值寻找完毕。最大值出现在队首。
补充:本题输出输出量巨大,需要使用输入输出外挂,并且是能处理负数的。
/*
ID: sdj22251
PROG: subset
LANG: C++
*/
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define LOCA
#define MAXN 1005*1005
#define INF 100000000
#define eps 1e-7
using namespace std;
int a[MAXN];
int q[MAXN];
int in()
{
int flag = 1;
char ch;
int a = 0;
while((ch = getchar()) == ' ' || ch == '\n');
if(ch == '-') flag = -1;
else
a += ch - '0';
while((ch = getchar()) != ' ' && ch != '\n')
{
a *= 10;
a += ch - '0';
}
return flag * a;
}
void out(int a)
{
if(a < 0) {putchar('-'); a = -a;}
if(a >= 10)out(a / 10);
putchar(a % 10 + '0');
}
int main()
{
int n, k;
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; i++)
a[i] = in();
int head = 0, tail = 0;
q[++tail] = 1;
for(int i = 1; i <= n; i++)
{
while(head <= tail && a[q[tail]] >= a[i])
tail--;
q[++tail] = i;
while(q[tail] - q[head] + 1 > k)
head++;
if(i == k)
out(a[q[head]]);
else if(i > k)
{
putchar(' ');
out(a[q[head]]);
}
}
putchar('\n');
head = 0, tail = 0;
q[++tail] = 1;
for(int i = 1; i <= n; i++)
{
while(head <= tail && a[q[tail]] <= a[i])
tail--;
q[++tail] = i;
while(q[tail] - q[head] + 1 > k)
head++;
if(i == k)
out(a[q[head]]);
else if(i > k)
{
putchar(' ');
out(a[q[head]]);
}
}
putchar('\n');
return 0;
}