题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1102
单调栈介绍
http://blog.csdn.net/liujian20150808/article/details/50752861
题解
对于每一个小块,我们都可以去求如果最终高度就是这个小块高度,左右可以延伸到多远。
普通dp可以做,复杂度虽然我不会证明但是不会超时。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=50000+20;
int n,a[maxn],l[maxn],r[maxn];
int main(void)
{
long long ans=-1;
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
l[1]=1;
a[0]=-1;
for(int i=2;i<=n;i++)
{
if(a[i]>a[i-1])
l[i]=i;
else//a[i]<=a[i-1]
{
l[i]=l[i-1];
while(a[i]<=a[l[i]-1])
l[i]--;
}
}
r[n]=n;
a[n+1]=-1;
for(int i=n-1;i>=1;i--)
{
if(a[i]>a[i+1])
r[i]=i;
else
{
r[i]=r[i+1];
while(a[i]<=a[r[i]+1])
{
r[i]++;
}
}
}
for(int i=1;i<=n;i++)
{
long long len=r[i]-l[i]+1;
ans=max(ans,len*a[i]);
}
cout<<ans<<endl;
return 0;
}
用单调栈则方便易懂,更重要的是,实现了O(n)的复杂度。具体就是从左往右找对于每一个小块,其左边出现的第一个高度小于它的小块的座标;从右往左找对于每一个小块,其右边出现的第一个高度小于它的小块的座标。
#include<set>
#include<iostream>
#include<stack>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=50000+10;
int a[maxn],l[maxn],r[maxn],n;
stack<int> s1,s2;
int main(void)
{
long long ans=-1;
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
a[0]=a[n+1]=0;
s1.push(0);
s2.push(n+1);
for(int i=1;i<=n;i++)
{
while(a[i]<=a[s1.top()])
s1.pop();
l[i]=s1.top()+1;
s1.push(i);
}
for(int i=n;i>=1;i--)
{
while(a[i]<=a[s2.top()])
s2.pop();
r[i]=s2.top()-1;
s2.push(i);
}
for(int i=1;i<=n;i++)
{
long long temp=(long long)a[i]*(r[i]-l[i]+1);
ans=max(ans,temp);
}
cout<<ans<<endl;
return 0;
}