zoukankan      html  css  js  c++  java
  • 「日常训练」Mike and Feet(Codeforces Round #305 Div. 2 D)

    题意 (Codeforces 548D)

    对一个有$n$个数的数列,我们要求其连续$x(1le xle n)$(对于每个$x$,这样的连续group有若干个)的最小数的最大值。

    分析

    这是一道用了单调栈的题目,用的贼好。算是第一次应用吧。
    我们定义$l_i$为左侧比第$i$个数小的数的下标的最大值(没有就是0);$r_i$就是右侧比第$i$个数小的数的下标的最小值(没有就是$n+1$)。这样定义完后,我们会发现,$a_i$是$[a_{l_i+1},a_{r_i-1}]$的最小值,也就是size为$1,2,...,r_i-l_i-1$的最小值。这是可以线性地实现的,利用单调栈。具体实现见代码。
    接下来就要更新答案。粗一看好像只有$O(n^2)$的更新方法。但是同样有线性的更新方法。维护一个$ans$数组,里面放了长度为$i$的时候的最大值。那么初始时,对每个$ans_i$作赋值(利用前面的两个数组并取最大值——要用最大值嘛)。接下来就是线性的骚操作:我们知道$ans_i$是$1,2,...,i$的最小值,那么倒过来逐对比较更新就可以了。
    这样一来,就能用$O(3n)$的算法解决。

    代码

    #include <bits/stdc++.h>
    #define MP make_pair
    #define PB push_back
    #define fi first
    #define se second
    #define ZERO(x) memset((x), 0, sizeof(x))
    #define ALL(x) (x).begin(),(x).end()
    #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
    #define per(i, a, b) for (int i = (a); i >= (b); --i)
    #define QUICKIO                  
        ios::sync_with_stdio(false); 
        cin.tie(0);                  
        cout.tie(0);
    using namespace std;
    using ll = long long;
    using ull = unsigned long long;
    using pi = pair<int,int>;
    const int MAXN=200000;
    // After reading the editorial.
    
    int main()
    {
    QUICKIO
        int n,arr[MAXN+5];
        cin>>n; rep(i,1,n) cin>>arr[i];
        int l[MAXN+5],r[MAXN+5];
        stack<int> s;
        rep(i,1,n)
        {
            while(!s.empty() && arr[s.top()]>=arr[i])
                s.pop();
            if(s.empty())
                l[i]=0;
            else
                l[i]=s.top();
            s.push(i);
        }
        s=stack<int>();
        per(i,n,1)
        {
            while(!s.empty() && arr[s.top()]>=arr[i])
                s.pop();
            if(s.empty())
                r[i]=n+1;
            else
                r[i]=s.top();
            s.push(i);
        }
        int ans[MAXN+5]; memset(ans,-1,sizeof(ans));
        rep(i,1,n)
        {
            int len=r[i]-l[i]-1;
            ans[len]=max(ans[len],arr[i]);
        }
        per(i,n-1,1) ans[i]=max(ans[i],ans[i+1]);
        rep(i,1,n)
        {
            cout<<ans[i];
            if(i==n)cout<<endl;
            else cout<<" ";
        }
        return 0;
    }

    引申

    单调栈还有些类似的题目:HDU 1506、HDU 5033、POJ 2796、POJ 3250。
    类似的还有单调队列。
    题解将会之后补上。

    如非注明,原创内容遵循GFDLv1.3发布;其中的代码遵循GPLv3发布。
  • 相关阅读:
    GhostBSD 3.0RC3,基于GNOME的FreeBSD
    Nagios 3.4.3 发布,企业级监控系统
    Jolokia 1.0.6 发布, JMX远程访问方法
    微软希望开发人员不要使 WebKit 成为新版 IE6
    Kwort Linux 3.5 正式版发布
    EJDB 1.0.24 发布,嵌入式 JSON 数据库引擎
    Pale Moon 15.3 Firefox“苍月”优化版发布
    Galera Load Balancer 0.8.1 发布
    SmartSVN V7.5 正式发布
    PostgresQL建立索引如何避免写数据锁定
  • 原文地址:https://www.cnblogs.com/samhx/p/CFR305D2D.html
Copyright © 2011-2022 走看看