题意
给定n()个连续的长为a[i]而宽为1的矩形,求这些矩形拼接成的图形的最大子矩形的面积。题目有多组样例,当输入的n为0时停止。
![](https://i-blog.csdnimg.cn/blog_migrate/a73d14e78d8c7cc7f24b2b73fb0c3788.gif)
思路
假定这些矩形的高度都是单调递增的,那么答案呼之欲出:(高度*它到最后一个矩形的距离)的最大值!但是很遗憾,这些矩形并非单调递增——但也提供了切入点。
考虑下一个矩形比这个矩形矮的情况:如果该矩形和下一个矩形都被选中,那么所组成的矩形高度必定小于等于下一个矩形(换言之:该矩形上面那一块此时已经无用),那么如果我们刷新一遍不选下一个矩形而选入该矩形的情况,就可以安枕无忧地将这两个矩形“合并”。
考虑到前面的矩形已经都被“合并”过,因此前面的矩形组成了一个单调递增的序列,此时我们考虑用上单调栈。每次合并得到的矩形可能比前一个还矮,那就再来一次合并!一直如此,直到没得合并或所得矩形高于栈顶矩形,然后再把这个合并后的庞然大物压入栈顶。每个矩形只会来一次,走一次,时间复杂度满足要求。
那么对于每个矩形,它的最大面积如何计算?考虑合并时的操作,合并时实际上是对一个单调递增的序列求最大子矩形的面积,且要求这个子矩形包括该矩形,那么答案又呼之欲出了:(高度*它到最后一个矩形的距离)!此时的”最后一个矩形“指的是”合并“操作前的栈顶矩形,取出了几个,距离就是多少,然后用一个ans去记录最大值。
代码
#include <iostream>
#include <stack>
using namespace std;
stack<pair<long long, long long> > s;
int n;
long long a[100005];
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
while (true) {
long long ans = 0;
cin >> n;
if (n == 0)
return 0;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
a[n + 1] = 0;
for (int i = 1; i <= n + 1; ++i) {
long long t = 0;
while (!s.empty() && a[i] < s.top().first) {
t += s.top().second;
ans = max(ans, t * s.top().first);
s.pop();
}
s.push(make_pair(a[i], t + 1));
}
cout << ans << '\n';
}
}