Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 25276 | Accepted: 8167 |
Description
Input
Output
Sample Input
7 2 1 4 5 1 3 3 4 1000 1000 1000 1000 0
Sample Output
8 4000
Hint
n的范围是1e5,即使是用n*n的动态规划来写,也是会超时的。
我们用单调栈可以在O(n)的复杂度下解决。
单调栈,也就是栈内的元素是按照某种顺序有序排列的。
在新的元素将要入栈的时候,如果满足单调性,就直接入栈。
如果不满足的话,就弹出栈内的元素,直到满足后入栈。
用法:用来求出某个数的左边和右边第一个大于或小于它的元素,时间复杂度O(n)。
我们枚举每一个小矩形的高度,以该高度为最低限度,然后向两边进行延伸。
向左延伸的时候,延伸到第一个小于该最低限度的矩形的时候结束,向右也是,
延伸到第一个小于该最低限度的矩形的时候结束。
也就是求左边和右边第一个小于它的元素
因为我们可以用单调栈来解决。
维护一个严格单调递增的单调栈。
向左求出第一个小于它的元素的位置+1,也就是可以想左延伸的最长距离
向右求出第一个大于它的元素的位置-1,也就是可以向右延伸的最长距离
AC代码
#include
#include
#include
#define maxn 100005
#define LL long long
using namespace std;
int n;
LL h[maxn];
LL l[maxn];
LL r[maxn];
stack s;
int main()
{
while(~scanf("%d",&n))
{
if(n==0)
break;
for(int i=1; i<=n; i++)
{
scanf("%lld",&h[i]);
}
while(!s.empty())
{
s.pop();
}
for(int i=1; i<=n; i++)
{
while(!s.empty()&&h[s.top()]>=h[i])
{
s.pop();
}
if(s.empty())
l[i]=1;
else
l[i]=s.top()+1;
s.push(i);
}
while(!s.empty())
{
s.pop();
}
for(int i=n; i>=1; i--)
{
while(!s.empty()&&h[s.top()]>=h[i])
{
s.pop();
}
if(s.empty())
r[i]=n;
else
r[i]=s.top()-1;
s.push(i);
}
LL ans=-1;
for(int i=1; i<=n; i++)
{
ans=max(ans,h[i]*(r[i]-l[i]+1));
}
printf("%lld\n",ans);
}
return 0;
}