求相邻最大矩形面积
问题描述
青石板路的尽头堆满了财宝。小 L 感到很一阵阵失望,只能先搬走一部分财宝了。
财宝是一个个矩形紧紧挨在一起,第 i 个矩形宽度为 1 ,高度是 h i h_i hi
小 L 是一个 不会贪心 不贪心的人,所以决定只拿走最大矩形的面积这么多。
拿着拿着,小 L 突然想到,其实这个财宝墙后面还是有路的。
输入格式
第一行一个整数 n , n≤105
第二行,一行数,第 i 个数代表 *
h
i
h_i
hi , 0≤
h
i
h_i
hi*≤109
输出格式
一行,一个数,代表最大矩形面积
样例输入
7
2 1 4 5 1 3 3
样例输出
8
算法思想:
循环每一个条形(下标是 i),找左边第一个小于当前条形高度的下标left,找右边第一个小于当前条形高度的下标right。
那么根据不让其他条形拖自己后腿、只想自己抱大腿的思想,这个条形算出的矩形面积就是
(条形值[right - 1] - 条形值[left + 1]) * 条形值[i]
但是注意!!这里的right - 1 / left + 1是广义的,你不要让他减 1 或者加 1 之后把自己都越过去了。好歹判断一下范围。
这题比较阴险,直接用单调栈计算左边第一个小于当前条形高度的下标 left,找右边第一个小于当前条形高度的下标 right 还会超时。得优化一下。
注意!!!!栈里放的是元素下标!!!!!(下面都直接用元素代替,知道具体是元素下标就好,下面的打的太赶了)
优化方法:用一个单调递减栈,每次放进一个元素的时候,如果发现当前元素比栈顶元素小,很好,这样就可以发现栈顶元素往右第一个比栈顶元素小的值。
而根据单调递减栈的定义,栈中每一个元素的下一个元素(就是朝着栈底的下一个)就是他往左第一个比他小的值的下标,就是上面的 left。那这样不就找到了以栈顶元素为木桶原理中最短板的矩形吗。
注意噢,最后一个元素放完的时候,栈里面的哪些元素都是还没有判断面积的,都要一个个取出来判断一下这些元素形成的矩形的面积。而且他们的右界的 right 就是 n - 1,因为都比当前栈顶元素大。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll num[10000000] = {0};
ll revnum[10000000] = {0};
int main()
{
ll n;
cin >> n;
for (ll i = 0; i < n; i++)
{
cin >> num[i];
}
ll mianji = 0;
stack<ll> s;//单调递减栈
for (ll i = 0; i < n;)
{
if (s.size() == 0 || num[s.top()] <= num[i])
{
s.push(i);
i++;
}
else
{
//此时计算以num[a]为矩形的高的情况
ll a = s.top();
s.pop(); //此时s.top()就是离下标为a的元素的左边的第一个最小值,而i是离下标为a的元素的右边的第一个最小值
if (s.size() == 0)
mianji = max(mianji, num[a] * (i - a));
else
mianji = max(mianji, num[a] * (i - s.top() - 1));
}
}
//最后一次一定是放进了下标n-1
//对s中每一个数他的矩形长都可以直接到n,因为此时举行中放的下标所对应的值都是小于等于n-1所对应的值的
while(s.size() != 0)
{
ll a = s.top();
s.pop();
if(s.size() == 0)
mianji = max(mianji,num[a] * (n - a));
else
mianji = max(mianji,num[a] * (n - s.top() - 1));
}
cout << mianji << endl;
return 0;
}