题意:
在二维坐标上,有n个相邻的矩形,每个矩形的宽为单位长度,高不相同,问能组成的最大子矩形面积。
配合图片使用更佳:
阴影部分即样例的最大矩形。
解题思路:
我们考虑每一个单位矩形,它能否以自己的高度和相邻的矩形组成一个新的矩形取决于旁边的矩形的高度是否不小于它,那么,我们如果能知道一个矩形左边第一个高度小于它的矩形的位置l,右边第一个高度小于它的矩形的位置r,那么我们就能知道以这个矩形的高为高能形成新的最大矩形的面积(r-l-1)*height。
那么怎么求出l,r呢,我们只需要从前往后,从后往前分别跑一遍单调栈(递增),就能维护出每一个矩形的l,r。
单调递增栈在压栈的时候,让栈顶开始所以高度大于等于自己的元素都出栈,这时候栈顶的元素就是第一个小于自己高度的元素了,就求出目标矩形的位置了,然后自己再入栈,继续维护。
代码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#define LL long long
using namespace std;
const int maxn=1e5+5;
struct p
{
LL height;
LL l;
LL r;
}a[maxn];
int in[maxn];
int main()
{
int n, i, j;
while(~scanf("%d", &n))
{
if(n==0)break;
int top=0;
for(i=0; i<n; i++)a[i].l=a[i].r=0;
for(i=0; i<n; i++)
{
scanf("%lld", &a[i].height);
if(top==0)
{
in[++top]=i;
a[i].l=-1; //左边没有值就是左边没有元素小于自己
}
else
{
while(top>0 && a[in[top]].height>=a[i].height)
{
top--;
}
if(top>0)a[i].l=in[top];
else a[i].l=-1; //左边没有元素小于自己
in[++top]=i;
}
}
top=0;
for(i=n-1; i>=0; i--)
{
if(top==0)in[++top]=i, a[i].r=n;
else
{
while(top>0 && a[in[top]].height>=a[i].height)
{
top--;
}
if(top>0)a[i].r=in[top];
else a[i].r=n;
in[++top]=i;
}
}
LL x, ans=0;
for(i=0; i<n; i++)
{
// printf("%d %lld %lld\n", i, a[i].l, a[i].r);
x=a[i].height*(a[i].r-a[i].l-1LL);
ans=x>ans?x:ans;
}
printf("%lld\n", ans);
}
}