• hdu1506 直方图中最大的矩形 单调栈入门


    hdu1506 直方图中最大的矩形 单调栈入门

    直方图是由在公共基线对齐的矩形序列组成的多边形。矩形具有相同的宽度,但可能具有不同的高度。例如,左侧的数字显示了由高度为2,1,4,5,1,3,3的矩形组成的直方图,单位为1,其中矩形的宽度为1:

    通常,直方图用于表示离散分布,例如文本中字符的频率。请注意,矩形的顺序,即它们的高度很重要。计算在公共基线上对齐的直方图中最大矩形的面积。右图显示了所描述的直方图的最大对齐矩形。

    输入包含几个测试用例。每个测试用例都描述一个直方图,并以整数n开头,表示它组成的矩形的数量。您可以假设1 <= n <= 100000。然后遵循n个整数h1,...,hn,其中0 <= hi <= 1000000000。这些数字表示直方图的矩形的高度,从左到右订购。每个矩形的宽度是1.零跟在最后一个测试用例的输入之后。对于每个测试用例,在一行中输出指定直方图中最大矩形的面积。请记住,这个矩形必须在公共基线上对齐。

    单调栈,就是具有单调性质的栈,用途与单调队列有相似之处。我们先来分析一下这道题。一个最大矩阵的高度,就是矩阵覆盖到的,高度最小的条形的高度。所以我们只需要枚举每个条形作为高度最小的条形,所能形成的最大矩阵,然后取最大值即可。

    那么现在,问题就转换成了对于每个条形,以它的高度作为矩阵的高度,矩阵最多能向左和向右延伸到的高度,相当于求这个矩阵,左边有连续多少个矩阵比它高,右边有连续多少个矩阵比它高。所以,长度就是:(右边第一个比它小的条形的位置-左边第一个比它小的条形的位置-1)。如何求第一个比当前数小的左侧或右侧数呢?这就要用到单调栈。

    设第一个比当前数(序号为i)小的左侧数为(left[i])。算法的流程是这样的:设现在程序循环到第i个数,如果当前,栈顶的数大于等于第i个数,说明什么?说明序号i以后的数j,它们的(left[j])一定不会是栈顶那个数,因为选了j一定能选i。既然这样,直接把j从栈中弹出,然后继续判断……直至第i个数遇到比它小的栈顶的数。这个数就是(left[i]),因为比i小的数只会被更小更优的数替换。然后,将i入栈。这样就把那些无用的,值大于第i个数,却在第i个数左边的数统统用第i个数替换了。这就去除了冗余状态。

    从这道题,我们能发现一些单调栈和单调队列的共同点和不同点。共同点:1.它们都保持了单调性。2.它们都通过一个元素必定比其它优,就可以直接删去其他元素的方法,去除了冗余状态。3.由于元素都是一进一出,时间复杂度为O(n)。不同点:单调队列,最优值和插入操作在队首,在弹出操作在队尾。单调栈,最优值,插入操作和弹出操作都在栈顶。

    #include <cstdio>
    using namespace std;
    
    const int maxn=1e5+5;
    typedef long long LL;
    struct stack{
        int t, a[maxn];
        void reset(){ t=0; }
        void pop(){ if (--t==-1) ++t; }
        void add(int x){ a[++t]=x; }
        int top(){ return a[t]; }
    }s;
    
    int n;
    int a[maxn], lessleft[maxn], lessright[maxn];
    
    int max(const int &a, const int &b){ return a<b?b:a; }
    LL max(const LL &a, const LL &b){ return a<b?b:a; }
    
    int main(){
        while (scanf("%d", &n), n){
            a[0]=a[n+1]=-1;
            s.reset(); s.add(0);
            for (int i=1; i<=n; ++i){
                scanf("%d", &a[i]);
                while (a[i]<=a[s.top()]) s.pop();
                lessleft[i]=s.top(); s.add(i);
            }
            s.reset(); s.add(n+1);
            for (int i=n; i>=1; --i){
                while (a[i]<=a[s.top()]) s.pop();
                lessright[i]=s.top(); s.add(i);
            }
            LL maximum=0;
            for (int i=1; i<=n; ++i)
                maximum=max(maximum,
                    LL(lessright[i]-lessleft[i]-1)*a[i]);
            printf("%lld
    ", maximum);
        }
        return 0;
    }
    
  • 相关阅读:
    chrome输入框记住密码导致背景黄色的解决方案
    死活要居中(转载)
    Google HTML/CSS/JS代码风格指南
    CSS的inherit与auto使用分析
    photoshop中rgb与索引模式的区别
    placeholder调整颜色
    你应该了解的5个JavaScript调试技巧
    HTML TAG FROM MDN
    apple iphone 3gs 有锁机 刷机 越狱 解锁 全教程(报错3194,3014,1600,短信发不出去等问题可参考)
    史上最全的CSS hack方式一览
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/8433016.html
Copyright © 2020-2023  润新知