题目大意:给定一个长度为 N 的序列,求任意区间 [ l , r ] 中最小的(min{v[i],iin[l,r] }*Sigma_{i=l}^rv[i])。
题解:这是一道具有标准单调栈特征的问题,即:区间最小值贡献类问题。直接枚举每个点为最小值时用单调栈求出左右最远的延伸距离,并利用前缀和预处理进行答案统计即可。
代码如下
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=1e5+10;
inline int read(){
int x=0,f=1;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
return f*x;
}
int n,v[maxn],stk[maxn],top,l[maxn],r[maxn];
long long ans=-1,sum[maxn];
void read_and_parse(){
n=read();
for(int i=1;i<=n;i++)v[i]=read(),sum[i]=sum[i-1]+v[i];
}
void solve(){
v[0]=v[n+1]=-1;//这里卡了半天 QAQ
for(int i=1;i<=n+1;i++){
while(top&&v[stk[top]]>v[i])r[stk[top--]]=i-1;
stk[++top]=i;
}
top=0;
for(int i=n;i>=0;i--){
while(top&&v[i]<v[stk[top]])l[stk[top--]]=i+1;
stk[++top]=i;
}
int x,y;
for(int i=1;i<=n;i++){
long long src=(sum[r[i]]-sum[l[i]-1])*v[i];
if(src>ans)ans=src,x=l[i],y=r[i];
}
printf("%lld
%d %d
",ans,x,y);
}
int main(){
read_and_parse();
solve();
return 0;
}