[LG1886]滑动窗口 单调队列

~~~题面~~~

题解:

  观察数据范围,这应该是一个复杂度O(n)的题。以最大值为例,考虑单调队列,维护一个单调递减的队列。从前向后扫,每次答案取队首,如果后面进入的比前面大,那么就弹出前面的数,因为是从前向后扫,所以后面进入的如果比前面的大,那么一定更优,因为要淘汰肯定先淘汰前面的。如果队首已经不在当前窗口内了,那么就弹出,直到合法为止。

  维护单调队列时的一个重要原则就是把别人“挤掉”的元素一定要比被挤掉的元素更优,否则可能找不到合法情况or漏掉最优解。注意这一点就很好理解了。

  最小值用求最大值相反的操作即可

  不知道为什么我以前写代码写那么丑,,,,重新写一份好了。

 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 }
View Code

   当然如果你喜欢简短的代码,且不在意常数问题,你也可以这么写:

 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 }
View Code

猜你喜欢

转载自www.cnblogs.com/ww3113306/p/9780397.html
今日推荐