AcWing131. 直方图中最大的矩形
直方图的最大面积
题意
直方图是由在公共基线处对齐的一系列矩形组成的多边形。
矩形具有相同的宽度,但可以有不同的高度。
例如,下图显示了高度为 \(2, 1, 4, 5, 1, 3, 3\) 的矩形组成的直方图。
请问直方图上最大的对齐矩阵面积为多少?
分析
首先可以发现最大的对齐矩阵的高度,一定是某个矩形的高度。
暴力分析,对每一个矩阵 \(i\),我们假设它的高度 \(h(i)\) 为最大面积的高度,求出从这个矩形开始向左右最多扩展多少,假设最多扩展到 \([l, r]\) 那么其面积为 \((r - l + 1) \times h(i)\) 。只要求出所有这样的矩形最大值即可。
考虑优化,对于矩形 \(i\) ,假设 \(j \lt k \lt i\) ,且 \(h(j) > h(k)\) ,那么我们不需要考虑 \(h(j)\) 。因为如果 \(h(k) >= h(i)\) 那么一定有 \(h(j) >= h(i)\) ,所以可以用单调栈优化。
从前往后找出每个矩形最多扩展的左端点,右端点同理。
Code
#include <iostream>
using namespace std;
const int N = 100010;
// 单调栈优化暴力,l[i] 存储i号矩形向左的界限
int stk[N], top, l[N], r[N];
int n, a[N];
int main ()
{
while( cin >> n, n )
{
top = 0;
for (int i = 1; i <= n; i ++ ) cin >> a[i];
// 找出每个矩形左界限
for (int i = 1; i <= n; i ++ )
{
while(top && a[stk[top]] >= a[i]) -- top;
if (!top) l[i] = 1; else l[i] = stk[top] + 1;
stk[++ top] = i;
}
top = 0;
// 找出每个矩形的右界限
for (int i = n; i >= 1; i -- )
{
while(top && a[stk[top]] >= a[i]) -- top;
if (!top) r[i] = n; else r[i] = stk[top] - 1;
stk[++ top] = i;
}
long long mx = -1;
for (int i = 1; i <= n; i ++ )
{
int le = l[i], ri = r[i];
long long cur = 1ll * (ri - le + 1) * a[i];
mx = max(mx, cur);
}
cout << mx << endl;
}
return 0;