UVA1619 感觉不错 Feel Good(单调栈)
题意:
给出正整数n和一个(1 <= n <= 100 000)长度的数列,要求找出一个子区间,使这个子区间的数字和乘上子区间中的最小值最大。输出这个最大值与区间的两个端点。
思路:
单调栈,预处理出每个点能到的最左,右点;再来个前缀和预处理
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+10;
ll n,a[maxn],he[maxn],p[maxn],top,zuo[maxn],you[maxn];
int main(){
int t=0;
while(~scanf("%lld",&n)){
if(t++)printf("\n");
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
he[i]=he[i-1]+a[i];
}
for(int i=n;i;i--){
while(top&&a[i]<a[p[top]]){
zuo[p[top--]]=i+1;
}
p[++top]=i;
}
while(top)zuo[p[top--]]=1;
for(int i=1;i<=n;i++){
while(top&&a[i]<a[p[top]]){
you[p[top--]]=i-1;
}
p[++top]=i;
}
while(top)you[p[top--]]=n;
ll ans=0,l=1,r=1;
for(int i=1;i<=n;i++){
ll sum=(he[you[i]]-he[zuo[i]-1])*a[i];
if(sum>ans){
ans=sum,l=zuo[i],r=you[i];
}
}
printf("%lld\n%lld %lld\n",ans,l,r);
}
}