poj 2823 Sliding Window 单调队列
poj 2823 Sliding Window
//poj 2823 Sliding Window //单调队列 //以下是复制别人的思路的,自己写的代码过不了,这代码也是模仿别人的 //这题还可以用单调队列进行求解。开两个队列,一个维护最大值, //一个维护最小值。下面叙述最大队列,最小队列的方法类似。 //最大队列保证队列中各个元素大小单调递减(注意,不是单调不上升), //同时每个元素的下标单调递增。这样便保证队首元素最大,而且更新的 //时候队首永远是当前最大。因此,这个队列需要在两头都可以进行删除, //在队尾插入。 //维护方法:在每次插入的时候,先判断队尾元素,如果不比待插入元素 //大就删除,不断删除队尾直到队尾元素大于待插入元素或者队空。删除 //的时候,判断队首,如果队首元素下标小于当前段左边界就删除,不断 //删除队首直到队首元素下标大于等于当前段左边界(注意:这时队列肯 //定不为空),队首元素就是当前段的最优解。 #include <stdio.h> #include <string.h> #define N 1000005 int input() { char ch; int sign = 1, num = 0; while(ch = getchar(), ch == '\n' || ch == ' '); if(ch == EOF) return EOF; if(ch == '-') { sign = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { num = num * 10 + ch - '0'; ch = getchar(); } return sign * num; } int arr[N], mn[N], mx[N], time[N], ans[N]; int len, k; void getMin() { int head = 1, tail = 0; for(int i = 1; i <= len; ++i) { //删除队尾比要插入的数大的数 while(head <= tail && mn[tail] >= arr[i]) tail--; mn[++tail] = arr[i]; //把要插入的数插入到队尾,因此 time[tail] = i; //队列后面的数肯定比前面的数晚过期 if(i >= k) { while(time[head] <= i - k)//注意:这里要等,eg:当i=k+1时 head++; //第一个就过期了 ans[i-k] = mn[head]; } } } void getMax() { int head = 1, tail = 0; for(int i = 1; i <= len; ++i) { while(head <= tail && mx[tail] <= arr[i]) tail--; mx[++tail] = arr[i]; time[tail] = i; if(i >= k) { while(time[head] <= i - k) head++; ans[i-k] = mx[head]; } } } void print() { int end = len-k; //总的有 1+end 组 宽度为 k 的数 for(int i = 0; i <= end; ++i) { printf("%d", ans[i]); if(i != end) putchar(' '); } puts(""); } int main() { while(scanf("%d%d", &len, &k) != EOF) { for(int i = 1; i <= len; ++i) arr[i] = input(); getMin(); print(); getMax(); print(); } return 0; }