zoukankan      html  css  js  c++  java
  • [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("
    ");    
    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("
    ");
    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("
    ");    
    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
  • 相关阅读:
    NYOJ 625 笨蛋的难题(二)
    NYOJ 102 次方求模
    ZJU Least Common Multiple
    ZJUOJ 1073 Round and Round We Go
    NYOJ 709 异形卵
    HDU 1279 验证角谷猜想
    BNUOJ 1015 信息战(一)——加密程序
    HDU 1202 The calculation of GPA
    "蓝桥杯“基础练习:字母图形
    "蓝桥杯“基础练习:数列特征
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9780397.html
Copyright © 2011-2022 走看看