题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1102
题意:
分析:
这题及得好像在哪做过QAQ,很快就水掉了,
刚开始想的是枚举每个ai,然后向两边 找大于等于ai的最大范围Li和Ri,更新答案ans=max(ans,(R[i]-L[i]+1)*ai)。很容易想到预处理Li和Ri,因为if(a[i-1]>=a[i])那么L[i]至少是L[i-1],求R[i]同理。时间复杂度最多O(nlogn)
叙述的不清楚,还是看这篇吧:http://blog.csdn.net/queuelovestack/article/details/52326276
看到标签是单调栈。维护一个递减的栈,栈中保存对应ai的下标,如果ai>栈顶元素,那么直接放入栈顶。否则,一直弹栈,知道栈顶元素小于ai为止,那么此时弹出的元素个数都是比栈顶元素大的,也就是可以组合矩形,这样的话就可以更新最大值了。
需要注意的细节是,因为栈中保存的是递减的,所以相同值得元素保存最小的那个位置就行了。
为了最后一次把所有的值都计算,最后把-1压栈在计算下即可。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e4+9;
ll a[N];
int main() {
int n;
ll ans=0;
stack<int>s;
scanf("%d",&n);
while(!s.empty()) s.pop();
for(int i=0; i<n; i++)
scanf("%lld",&a[i]);
a[n]=-1;
for(int i=0; i<=n; i++) {
if(s.empty()||a[i]>a[s.top()]) {
s.push(i);
} else if(a[i]<a[s.top()]) {
int t=i;
while(!s.empty()&&a[i]<a[s.top()]) {
ans=max(ans,(i-s.top())*a[s.top()]);
t=s.top();
s.pop();
}
s.push(t);
a[t]=a[i];
}
}
printf("%lld\n",ans);
return 0;
}