解:
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; }