【POJ2796】Feel Good 单调栈

题目大意:给定一个长度为 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;
}
原文地址:https://www.cnblogs.com/wzj-xhjbk/p/10066610.html