[LG1886]滑动窗口 单调队列
题解:
观察数据范围,这应该是一个复杂度O(n)的题。以最大值为例,考虑单调队列,维护一个单调递减的队列。从前向后扫,每次答案取队首,如果后面进入的比前面大,那么就弹出前面的数,因为是从前向后扫,所以后面进入的如果比前面的大,那么一定更优,因为要淘汰肯定先淘汰前面的。如果队首已经不在当前窗口内了,那么就弹出,直到合法为止。
维护单调队列时的一个重要原则就是把别人“挤掉”的元素一定要比被挤掉的元素更优,否则可能找不到合法情况or漏掉最优解。注意这一点就很好理解了。
最小值用求最大值相反的操作即可
不知道为什么我以前写代码写那么丑,,,,重新写一份好了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define AC 1001000 5 6 int n, k, head, tail; 7 int s[AC]; 8 struct node{ 9 int x, id; 10 }q[AC]; 11 12 inline int read() 13 { 14 int x = 0;char c = getchar(); bool z = false; 15 while(c > '9' || c < '0') 16 { 17 if(c == '-') z = true; 18 c = getchar(); 19 } 20 while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); 21 if(!z) return x; 22 else return -x; 23 } 24 25 void pre() 26 { 27 n = read(), k = read(); 28 for(R i = 1; i <= n; i ++) s[i] = read(); 29 } 30 31 void work1() 32 { 33 head = 1, tail = 0; 34 for(R i = 1; i <= n; i ++) 35 { 36 while(head <= tail && q[head].id <= i - k) ++ head; 37 while(s[i] < q[tail].x && head <= tail) -- tail;//可以删完,反正后面要塞进来 38 q[++tail] = (node){s[i], i}; 39 if(i >= k) printf("%d ", q[head].x); 40 } 41 printf("\n"); 42 } 43 44 void work2() 45 { 46 head = 1, tail = 0; 47 for(R i = 1; i <= n; i ++) 48 { 49 while(head <= tail && q[head].id <= i - k) ++ head;//,,,前面也可以删完 50 while(s[i] > q[tail].x && head <= tail) -- tail;//可以删完,反正后面要塞进来 51 q[++tail] = (node){s[i], i}; 52 if(i >= k) printf("%d ", q[head].x); 53 } 54 printf("\n"); 55 } 56 57 int main() 58 { 59 freopen("in.in", "r", stdin); 60 pre(); 61 work1(); 62 work2(); 63 fclose(stdin); 64 return 0; 65 }
当然如果你喜欢简短的代码,且不在意常数问题,你也可以这么写:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define AC 1001000 5 6 int n, k, head, tail; 7 int s[AC]; 8 struct node{ int x, id;} q[AC]; 9 10 void cal(int t) 11 { 12 head = 1, tail = 0; 13 for(R i = 1; i <= n; i ++) 14 { 15 while(head <= tail && q[head].id <= i - k) ++ head; 16 while(s[i] < q[tail].x && head <= tail) -- tail;//可以删完,反正后面要塞进来 17 q[++tail] = (node){s[i], i}; 18 if(i >= k) printf("%d ", q[head].x * t); 19 }printf("\n"); 20 } 21 22 int main() 23 { 24 scanf("%d%d", &n, &k); 25 for(R i = 1; i <= n; i ++) scanf("%d", &s[i]); 26 cal(1); 27 for(R i = 1; i <= n; i ++) s[i] = -s[i]; 28 cal(-1); 29 return 0; 30 }