标签:
Time Limit: 12000MS | Memory Limit: 65536K | |
Total Submissions: 40956 | Accepted: 12150 | |
Case Time Limit: 5000MS |
Description
Window position | Minimum value | Maximum value |
---|---|---|
[1 3 -1] -3 5 3 6 7 | -1 | 3 |
1 [3 -1 -3] 5 3 6 7 | -3 | 3 |
1 3 [-1 -3 5] 3 6 7 | -3 | 5 |
1 3 -1 [-3 5 3] 6 7 | -3 | 5 |
1 3 -1 -3 [5 3 6] 7 | 3 | 6 |
1 3 -1 -3 5 [3 6 7] | 3 | 7 |
Your task is to determine the maximum and minimum values in the sliding window at each position.
Input
Output
Sample Input
8 3 1 3 -1 -3 5 3 6 7
Sample Output
-1 -3 -3 -3 3 3 3 3 5 5 6 7
题意:给n个数,给定k(k<=n),求依次从左到右所有长度为k的连续区间的最小值和最大值。
解析:由于n的范围已经给到了10^6,直接暴力的时间复杂度为O( (n-k)*k ),显然不能满足要求,所以今天我们要学一个神奇的队列——单调队列。
单调队列,其实只需要两个数组就能实现。一个p[ ]用来存队列中元素在原数组中的下标,a[ ]用来存元素的值。单调队列用来维护区间最值。
维护最大值:首先把第一个元素a[0]进到队列中,然后从剩下的n-1个中依次取出一个a[i]跟对尾的元素比较,将队尾比a[i]小的元素全部出队(因为比a[i]小的元素不可能是区间的最大值了),然后在队尾插入a[i],并记录q[rear] = i;这样我们就能得到最大值的队列了,但是所对应的元素有可能不在我们要求的区间范围内,那么我们就需要把队首的元素一次弹出,直到队首元素在所求范围内时,这时的队首元素就是该区间的最大值了。
维护最小值:其余的步骤都跟维护最大值一样,只是从队尾删除的是比当前元素大的元素,注意此时队首是区间的最小值。
AC代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <cmath> #include <cstdlib> #include <ctime> using namespace std; #define INF 0x7fffffff #define LL long long #define LLL(a, b) a<<b #define RRR(a, b) a>>b #define MID(a, b) a+(b-a)/2 const int maxn = 1000000 + 10; int q[maxn], a[maxn]; //q[]在原队列中的下标, a[]元素 int n, k; void solve(){ //维护区间最小值 int front = 0, rear = 0; //初始化 q[++rear] = 1; //先把第一个元素入队列 for(int i=1; i<=n; i++){ while(front <= rear && a[ q[rear] ] >= a[i]) rear --; q[++rear] = i; while(q[rear] - q[front] + 1 > k) front ++; if(i == k) printf("%d", a[ q[front] ]); if(i > k) printf(" %d", a[ q[front] ]); } puts(""); //维护区间最大值 front = 0, rear = 0; q[++rear] = 1; for(int i=1; i<=n; i++){ while(front <= rear && a[ q[rear] ] <= a[i]) //从队尾删除元素 rear --; q[++rear] = i; while(q[rear] - q[front] + 1 > k) //查找在区间中的值 front ++; if(i == k) printf("%d", a[ q[front] ]); if(i > k) printf(" %d", a[ q[front] ]); } puts(""); } int main(){ #ifdef sxk freopen("in.txt", "r", stdin); #endif // sxk while(scanf("%d%d", &n, &k)!=EOF){ memset(a, 0, sizeof(a)); for(int i=1; i<=n; i++) scanf("%d", &a[i]); solve(); } return 0; }
哈哈,今天收获还可以,还要努力哈~~~
标签:
原文地址:http://blog.csdn.net/u013446688/article/details/42472819