1. 程式人生 > >[LG1886]滑動窗口 單調隊列

[LG1886]滑動窗口 單調隊列

別人 true inline span tps 一份 space close 什麽

~~~題面~~~

題解:

  觀察數據範圍,這應該是一個復雜度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

[LG1886]滑動窗口 單調隊列