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发布。
  • 相关阅读:
    Account group in ERP and its mapping relationship with CRM partner group
    错误消息Number not in interval XXX when downloading
    错误消息Form of address 0001 not designated for organization
    Algorithm类介绍(core)
    梯度下降与随机梯度下降
    反思
    绘图: matplotlib核心剖析
    ORB
    SIFT
    Harris角点
  • 原文地址:https://www.cnblogs.com/samhx/p/CFR305D2D.html
Copyright © 2011-2022 走看看