单调栈问题:
1、特征:
栈内的所有元素都保持一个单调性,
eg:
递增的单调栈:顶端元素永远大于下面的元素
递减的单调栈:顶端元素永远小于下面的元素;
2、作用:
寻找从左到右,和从右到左第一个大于/小于当前元素的位置。
以这篇文章的递木板倒水问题为例
思路:
记录当前元素递增的可扩展的最长的左边元素L数组,最长的右边元素R数组。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
const int maxn = 300300;
typedef long long LL;
LL a[maxn],L[maxn],R[maxn];
LL MAX(LL x,LL y){
return x>y?x:y;
}
int main(void)
{
stack <LL> st;
int n,i,j;
while(~scanf("%d",&n)&&n){
while(!st.empty()) st.pop();
st.push(0);
for(i=1;i<=n+1;i++){
if(i<=n) scanf("%lld",&a[i]);
else a[i] = 0;
L[i] = R[i] = i;
while(st.size()>1&&a[st.top()]>=a[i]){
R[st.top()] = i-1;
st.pop();
}
L[i] = st.top();
st.push(i);
}
LL ans = 0;
for(i=1;i<=n;i++){
ans = MAX(ans,(R[i]-L[i])*a[i]);
}
printf("%lld\n",ans);
}
return 0;
}
思路:和上一题的基本相同,就是用前缀和处理一下宽度。
#include<iostream>
#include<cstdio>
#include<stack>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn = 1000300;
LL a[maxn],L[maxn],R[maxn],h[maxn],pre[maxn]={0};
LL MAX(LL x,LL y){
return x>y?x:y;
}
int main(void)
{
stack <LL> st;
st.push(0);
int n,i,j;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%lld",&a[i]);
pre[i] = pre[i-1]+a[i];
}
for(i=1;i<=n+1;i++){
if(i<=n) scanf("%lld",&h[i]);
else h[i] = 0;
L[i] = R[i] = i;
while(st.size()>1&&h[st.top()]>=h[i]){
R[st.top()] = i-1;
st.pop();
}
L[i] = st.top();
st.push(i);
}
LL ans = 0;
for(i=1;i<=n;i++){
ans = MAX(ans,(pre[R[i]]-pre[L[i]])*h[i]);
}
printf("%lld\n",ans);
}