zoukankan      html  css  js  c++  java
  • [luogu] P1440 求m区间内的最小值

    题目描述

    一个含有n项的数列(n<=2000000),求出每一项前的m个数到它这个区间内的最小值。若前面的数不足m项则从第1个数开始,若前面没有数则输出0。

    输入输出格式

    输入格式:

    第一行两个数n,m。

    第二行,n个正整数,为所给定的数列。

    输出格式:

    n行,第i行的一个数ai,为所求序列中第i个数前m个数的最小值。

    输入输出样例

    输入样例#1: 
    6 2
    7 8 1 4 3 2
    
    输出样例#1: 
    0
    7
    7
    1
    1
    3 
    

    说明

    【数据规模】

    m≤n≤2000000

    很显而易见的板子题。想练练RMQ-ST

    但是MAXN = 2000000,用没有滚动数组RMQ-ST会MLE两个点。。。

     1 #include <cstdio>
     2 #include <algorithm>
     3 using namespace std;
     4 const int N = 2000010;
     5 
     6 int a[N];
     7 
     8 int mn[N][25];
     9 
    10 int n, m, q, l, r;
    11 
    12 struct RMQ {
    13     int log2[N];
    14     void init() { 
    15         for (int i = 0; i <= n; ++ i) log2[i] = (i == 0 ? -1 : log2[i >> 1] + 1);
    16         for (int j = 1; j < 20; ++ j)
    17             for(int i = 1; i + (1 << j) - 1 <= n; ++ i)
    18                 mn[i][j] = min(mn[i][j - 1], mn[i + (1 << j - 1)][j - 1]);
    19     }
    20     int query(int ql, int qr) { 
    21         int k = log2[qr - ql + 1];
    22         return min(mn[ql][k], mn[qr - (1 << k) + 1][k]);
    23     }
    24 }rmq;
    25 
    26 void work(){
    27     rmq.init();
    28     for (int i = 1; i <= n; ++ i) {
    29         if (i == 1) { printf("0
    "); continue; }
    30         r = i - 1;
    31         if (i - m <= 0) l = 1;
    32         else l = i - m;
    33         printf("%d
    ", rmq.query(l, r));
    34     }
    35 }
    36 
    37 int main(){
    38     scanf("%d%d", &n, &m);
    39     for(int i = 1; i <= n; ++ i) scanf("%d", a + i), mn[i][0] = a[i];
    40     work();
    41     return 0;
    42 }

    然而懒得写不会滚动数组

    所以用了简洁明了的单调队列

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<iostream>
     5 #include<algorithm>
     6 
     7 using namespace std;
     8 
     9 const int MAXN = 2000010;
    10 int head,tail;
    11 int n,k,a[MAXN];
    12 
    13 struct node {
    14     int data,id;
    15 } change;
    16 node que[MAXN];
    17 
    18 inline int read() {
    19     int num = 0, f = 1; char ch = getchar();
    20     while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    21     while (ch >= '0' && ch <= '9') { num = num * 10 + ch - '0'; ch = getchar(); }
    22     return num * f;
    23 }
    24 
    25 int main() {
    26     n = read(); k = read();
    27     for (int i = 1; i <= n; ++ i) a[i] = read(); 
    28     puts("0");
    29     change.data = a[1];
    30     change.id = 1;
    31     que[tail++] = change;
    32     for (int i = 2; i <= n; ++ i) {
    33         if (que[head].id < i - k) head++;
    34         printf("%d
    ",que[head].data);
    35         while (head < tail && a[i] <= que[tail-1].data) tail--;
    36         change.id = i;
    37         change.data = a[i];
    38         que[tail++] = change;
    39     }
    40     return 0;
    41 } 

    下面发一波滚动数组版的看码风就知道不是我写的

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 const int maxn = 2000005;
     6 int a[maxn],bp,n;
     7 int f[maxn][2]; 
     8 int g[maxn];
     9 
    10 int main() 
    11 {
    12     scanf("%d %d", &n,&bp);
    13     for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    14     //init
    15     int now=0;
    16     for (int i=1;i<=n;i++)
    17     {
    18         if ((1 << (now+1))<=i) ++now;
    19         g[i]=now;
    20     }
    21     int t = 0;
    22     printf("0
    ");
    23     now = 2;
    24     for (int j = 0; (1 << j) <= bp; ++j) 
    25     {
    26         t = 1 - t;
    27         if (j == 0) 
    28         {
    29             for (int i = 1; i <= n; ++i) f[i][t] = a[i];
    30         }
    31         else 
    32         {
    33             for (int i = 1; i <= n - (1 << j) + 1; ++i) 
    34             {
    35                 f[i][t] = min(f[i][1 - t], f[i + (1 << (j - 1))][1 - t]);
    36             }
    37         }
    38         while (now <= n && min(now - 1, bp) < (1 << (j + 1))) 
    39         {
    40             int l=now-bp;
    41             if (l<=0) l=1;
    42             int r=now-1;
    43             int x = g[r - l + 1];
    44             int ans = min(f[l][t], f[r - (1 << x) + 1][t]);
    45             printf("%d
    ",ans);
    46             ++now;
    47         }
    48     }
    49     return 0;
    50 }

    比较神奇的是,ZKW线段树也不会T掉看码风就知道这也不是我写的

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,m,tree[4000001];
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i)
            scanf("%d",&tree[n+i]);
        tree[2*n+1]=2e9;
        for(int i=n;i;--i)
            tree[i]=min(tree[i<<1],tree[i<<1|1]);//建树
        puts("0");
        for(int i=2;i<=n;++i)
        {
            int l=max(n,i-m-1+n),r=i+n;//zkw适合开区间查询
            int ans=2e9;
            while(l^r^1)//zkw线段树的查询
            {
                if(~l&1) ans=min(tree[l^1],ans);
                if(r&1) ans=min(tree[r^1],ans);
                l>>=1,r>>=1;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }

    The end

  • 相关阅读:
    nyoj_216_A problem is easy_201312051117
    nyoj_676_小明的求助_201312042142-2
    C# 堆和栈的区别?
    DataReader和DataSet区别
    SQLSERVER2008R2正确使用索引
    SQL Profiler工具简介
    (转)非常完善的Log4net详细说明
    SQL语句优化技术分析
    HashTable、HashSet和Dictionary的区别
    使用Nuget发布自己的类库包
  • 原文地址:https://www.cnblogs.com/hkttg/p/8876486.html
Copyright © 2011-2022 走看看