题目链接:https://www.acwing.com/problem/content/133/
题意:直方图是由在公共基线处对齐的一系列矩形组成的多边形。
矩形具有相等的宽度,但可以具有不同的高度。
例如,图例左侧显示了由高度为2,1,4,5,1,3,3的矩形组成的直方图,矩形的宽度都为1:
通常,直方图用于表示离散分布,例如,文本中字符的频率。
现在,请你计算在公共基线处对齐的直方图中最大矩形的面积。图例右图显示了所描绘直方图的最大对齐矩形。
数据范围
1≤n≤100000,
0≤hi≤1000000000
输入样例:
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0
输出样例:
8
4000
思路:其实不难发现对于第i个小矩形,只要找到左边第一个小于它的小矩形lefti,和右边第一个比它小的小矩形righti,那么以第i个小矩形为顶边的最大矩形面积为(righti - lefti - 1) * 宽;而关于第一个小于它的数怎么找最快,就可以想到之前做过的单调队列啦,在寻找左边第一个小于它的数时,左边的数严格满足递增趋势(可回顾单调队列的博客)。
代码实现:
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int n;
int h[N], q[N], l[N], r[N];
void get(int bound[N])
{
int tt = 0;
h[0] = -1;
for(int i = 1; i <= n; i ++ ){
while(h[q[tt]] >= h[i]) tt -- ;
bound[i] = q[tt];
q[ ++ tt] = i;
}
}
int main()
{
while(cin >> n, n){
for(int i = 1; i <= n; i ++ )
cin >> h[i];
//立一个标兵在队头
h[0] = -1;
get(l);
reverse(h + 1, h + n + 1);
get(r);
ll res = 0;
//因为之前翻转了一下,所有原本的下标变成了对称位置的下标,1ll是long long 形式的1
for(int i = 1, j = n; i <= n; i ++, j -- )
res = max(res, h[i] * (n + 1 - l[j] - r[i] - 1ll));
cout << res << endl;
}
return 0;
}