【题解】良好的感觉

题目链接

解:

dp题目。

先对题目分析一下:目的是让我们最大化区间中任意一段的和乘以它的最小值。

怎么办?

首先,据题目得知,前缀和一定是递增的,因为没有负数。

那么,我们可以得出结论,对于任意区间的最小值x,它的区间长度越大,它的贡献就越大。

那我们找它的右边和左边第一个小于它的值的下标就好了。

你想到了什么?

单调栈。

我们让一个下标进栈。每次,当栈顶元素大于当前元素时:

将栈顶出栈,并且栈顶的右端点就是当前的i.与此同时,将栈顶删除。

那么,它的左端点是啥呢?

当栈顶的元素小于当前值了,那么当前值的左端点就显然是栈顶了。

最后,将当前下标入栈。

还需要特判,当一个位置的左端点是空时,说明它是它以左所有区间(以它为右端点)的最小值,则将其设为0.

反之同理。

最后,对于每一个位置i,都对于它取MAX.

Code:

#include<iostream>
#include<cstdio>
#include<stack>
using namespace std;
int n,a[500000],L[500000],R[500000];
long long f[500000],ans,sum[500000];
long long q[500000],top;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);
        sum[i]=sum[i-1]+a[i];
    }
    for(int i=1;i<=n;++i){
        while(top&&a[q[top]]>=a[i])R[q[top--]]=i;
        L[i]=q[top];
        q[++top]=i;
    }
    for(int i=1;i<=n;++i){
        if(!L[i])L[i]=0;
        if(!R[i])R[i]=n;
    }
    for(int i=1;i<=n;++i)ans=max(ans,a[i]*(sum[R[i]-1]-sum[L[i]]));
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/h-lka/p/11281811.html