NC50965 Largest Rectangle in a Histogram

NC50965 Largest Rectangle in a Histogram

题目

题目描述

A histogram is a polygon composed of a sequence of rectangles aligned at a common base line. The rectangles have equal widths but may have different heights. For example, the figure on the left shows the histogram that consists of rectangles with the heights 2, 1, 4, 5, 1, 3, 3, measured in units where 1 is the width of the rectangles:
img
Usually, histograms are used to represent discrete distributions, e.g., the frequencies of characters in texts. Note that the order of the rectangles, i.e., their heights, is important. Calculate the area of the largest rectangle in a histogram that is aligned at the common base line, too. The figure on the right shows the largest aligned rectangle for the depicted histogram.

输入描述

The input contains several test cases. Each test case describes a histogram and starts with an integer n, denoting the number of rectangles it is composed of. You may assume that \(1 \leq n \leq 100000\) . Then follow n integers \(h1\dots hn\), where \(0 \leq h_i \leq 1000000000\). These numbers denote the heights of the rectangles of the histogram in left-to-right order. The width of each rectangle is 1. A zero follows the input for the last test case.

输出描述

For each test case output on a single line the area of the largest rectangle in the specified histogram. Remember that this rectangle must be aligned at the common base line.

示例1

输入

7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0

输出

8
4000

说明

Huge input, scanf is recommended.

题解

思路

知识点:单调栈。

如果枚举区间,获取区间最小直方,显然是很复杂的。因为区间不同导致的最小值不同,虽然可以用单调队列动态获取某一区间的最小值,但问题在于端点的可能有 \(n^2\) 个,所以复杂度是 \(O(n^2)\) 是不可接受的。

但是换一种角度,我们枚举直方,一共就 \(n\) 个,枚举 \(n\) 次即可。那么固定一个直方,最大的可伸展长度取决于左右第一个小于它的位置,找到长度乘以直方高度就是矩形面积了。

对于一个直方,左边最邻近小于用单调递增栈从左到右维护,右边同理从右到左维护,注意找到的位置是小于的那个直方的位置,而不是可伸展最大的位置,因此左边的需要加一,右边的需要减一。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>

using namespace std;

int h[100007];
int l[100007], r[100007];
///最大矩形高度肯定是某个矩形高度
///对于一个矩形,水平扩展距离取决于第一个比他小的,两边都是
///于是对每个矩形,用单调递增栈获得他左侧/右侧第一个比它小的矩形位置,就能知道左侧/右侧扩展距离
int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n;
    while (cin >> n, n) {
        for (int i = 0;i < n;i++) cin >> h[i];
        stack<int> s1;
        for (int i = 0;i < n;i++) {
            while (!s1.empty() && h[s1.top()] >= h[i]) s1.pop();
            l[i] = s1.empty() ? 0 : s1.top() + 1;///左侧大于等于的第一个位置
            s1.push(i);
        }
        stack<int> s2;
        for (int i = n - 1;i >= 0;i--) {
            while (!s2.empty() && h[s2.top()] >= h[i]) s2.pop();///一定是大于等于,于是栈就是严格递减栈,元素是最靠右的
            r[i] = s2.empty() ? n - 1 : s2.top() - 1;///右侧大于等于的最后一个位置
            s2.push(i);
        }
        long long ans = 0;
        for (int i = 0;i < n;i++)
            ans = max(ans, (r[i] - l[i] + 1LL) * h[i]);
        cout << ans << '\n';
    }
    return 0;
}
张贴在2