问题描述:
直方图是由在公共基线处对齐的一系列矩形组成的多边形。
矩形具有相等的宽度,但可以具有不同的高度。
例如,图例左侧显示了由高度为2,1,4,5,1,3,3的矩形组成的直方图,矩形的宽度都为1:
通常,直方图用于表示离散分布,例如,文本中字符的频率。
现在,请你计算在公共基线处对齐的直方图中最大矩形的面积。
图例右图显示了所描绘直方图的最大对齐矩形。
输入格式
输入包含几个测试用例。
每个测试用例占据一行,用以描述一个直方图,并以整数n开始,表示组成直方图的矩形数目。
然后跟随n个整数h1,…,hn。
这些数字以从左到右的顺序表示直方图的各个矩形的高度。
每个矩形的宽度为1。
同行数字用空格隔开。
当输入用例为n=0时,结束输入,且该用例不用考虑。
输出格式
对于每一个测试用例,输出一个整数,代表指定直方图中最大矩形的区域面积。
每个数据占一行。
请注意,此矩形必须在公共基线处对齐。
Sample Input
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0
Sample Output
8
4000
分析1:
单调栈基本应用:计算他与他右边第一个比他大的数之间有多少数
找出每个矩形左右两边大于等于他的有多少个数
即该矩形高度可以向左右拓展的最长范围
最后遍历一遍根据左右范围求面积最大值即可
ps:
code1的下面还有code2
把l和r数组的空间省下来了(但是感觉影响不是很大)
code1:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#define int long long
using namespace std;
const int maxm=1e5+5;
int a[maxm];
int stk[maxm];
int l[maxm],r[maxm];
int n;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
while(cin>>n,n){
for(int i=1;i<=n;i++){
cin>>a[i];
}
a[0]=a[n+1]=-1;//保证所有数都出栈
int head=0;
for(int i=1;i<=n+1;i++){
while(head&&a[i]<a[stk[head]]){
r[stk[head]]=i-1;
head--;
}
stk[++head]=i;
}
head=0;
for(int i=n;i>=0;i--){
while(head&&a[i]<a[stk[head]]){
l[stk[head]]=i+1;
head--;
}
stk[++head]=i;
}
int ans=0;
for(int i=1;i<=n;i++){
ans=max(ans,(r[i]-l[i]+1)*a[i]);
}
cout<<ans<<endl;
}
return 0;
}
分析2:
在将破坏栈单调性的元素出栈时,最后一次出栈的元素就是当前入栈元素能拓展到的最左位置,将其能拓展到的最左位置入栈,并更新对应位置的值。
当这种最左位置出栈的时候表明已经找到了最右位置,尝试更新答案
code2:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#define int long long
using namespace std;
const int maxm=1e5+5;
int a[maxm];
int stk[maxm];
int n;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
while(cin>>n,n){
for(int i=1;i<=n;i++){
cin>>a[i];
}
a[++n]=-1;
int ans=0;
int head=0;
for(int i=1;i<=n;i++){
if(head==0||a[i]>=a[stk[head]]){
stk[++head]=i;
}else{
int last=i;
while(head&&a[i]<a[stk[head]]){
last=stk[head];
ans=max(ans,(i-last)*a[last]);
head--;
}
stk[++head]=last;
a[last]=a[i];
}
}
cout<<ans<<endl;
}
return 0;
}