AcWing 直方图中最大的矩形

AcWing 直方图中最大的矩形

题目:

题解:

  • 单调栈。
  • 学OI二年了才去学这道经典题… …
  • 一种朴素做法就是每次以当前矩形的高为高,然后往左右两边找到第一个高度比自己小的矩形(也就是找到了左右边界),然后当前答案就是当前矩形高度 * (找到的右边界 - 找到的左边界 + 1)。最终答案就是在所有当前答案里取max。
  • 复杂度O(n^2),问题出在拓展边界这一步上。可以这样思考,如果当前矩形的高度<=前面的一个矩形,那么前面的一个矩形我可以直接删除它,因为下一次找第一个高度小于某矩形的时候,肯定会找到当前矩形而不会找到前面的一个矩形。
  • 进一步把刚才的思路抽象,就是以下流程:
    1. 建一个栈
    2. 对于当前矩形,只要栈的top>=当前矩形高度,就pop掉,直到top<当前矩形高度。那么top矩形的位置就是当前矩形所要找的左边界。
    3. 插入当前矩形
  • 那么找右边界同理。

  • 这样每个矩形只被访问到了一遍,复杂度为O(n),挺不错的!

#include <iostream>
#include <cstdio>
#include <stack>
#define N 100005
#define inf 0x7fffffff
#define int long long
using namespace std;

struct Node {int val, pos;};
int n, ans;
int a[N], l[N], r[N];

int read()
{
    int x = 0; char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
    return x;
}

signed main()
{
    while(scanf("%lld", &n) == 1)
    {
        if(!n) break;
        stack<Node> stk1; stk1.push((Node){-inf, 0});
        for(int i = 1; i <= n; i++) a[i] = read();
        for(int i = 1; i <= n; i++)
        {
            while(stk1.top().val >= a[i]) stk1.pop();
            l[i] = stk1.top().pos + 1;
            stk1.push((Node){a[i], i});
        }
        stack<Node> stk2; stk2.push((Node){-inf, n + 1});
        for(int i = n; i >= 1; i--)
        {
            while(stk2.top().val >= a[i]) stk2.pop();
            r[i] = stk2.top().pos - 1;
            stk2.push((Node){a[i], i});
        }
        ans = -inf;
        for(int i = 1; i <= n; i++) ans = max(ans, a[i] * (r[i] - l[i] + 1));
        printf("%lld\n", ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/BigYellowDog/p/11300755.html
今日推荐