2019南昌邀请赛预选赛 I. Max answer (前缀和+单调栈)

题目:https://nanti.jisuanke.com/t/38228

这题题解参考网上大佬的。

程序的L[i],R[i]代表a[i]这个点的值在区间 [L[i],R[i]] 中最小的并且能拓展到最左为L[i],最右为R[i]。

然后如果a[i]>0的情况就是 : a[i]*(Sum[R[i]]-Sum[L[i]-1])

如果a[i]<0那么这题就会变得复杂许多。需要预处理出Lmin[i],Rmin[i],Lmin[i]代表:以i为右端点的时候 Lmin[i]为左端点能得到区间和最小,Rmin[i]同理。

那么a[i]<0的最大值就是:a[i]*(Sum[ max(L[i],Lmin[i]) ]-Sum[ min(R[i],Rmin[i])-1 ])

具体细节可以看代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=5e5+10;
const int INF=0x3f3f3f3f;
LL n,top,a[N],L[N],R[N],Sum[N],Lmin[N],Rmin[N];
struct dat{
    LL idx,val;
}S[N];

int main()
{
    cin>>n;
    for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
    for (int i=1;i<=n;i++) Sum[i]=Sum[i-1]+a[i];
    
    a[n+1]=-INF;
    for (int i=1;i<=n+1;i++) {
        while (top && a[i]<S[top].val) {
            int id=S[top].idx;
            L[id]=S[top-1].idx+1; R[id]=i-1;
            top--;
        }
        top++; S[top].idx=i; S[top].val=a[i];
    }
    
    LL sum=0,Max=0,id=0;
    for (int i=1;i<=n;i++) {
        sum+=a[i]; 
        Lmin[i]=id+1;
        if (sum>Max) Max=sum,id=i;
    }
    sum=0; Max=0; id=n+1;
    for (int i=n;i;i--) {
        sum+=a[i];
        Rmin[i]=id-1; 
        if (sum>Max) Max=sum,id=i;
    }
    
    LL ans=-INF;
    for (int i=1;i<=n;i++)
        if (a[i]>=0) ans=max(ans,a[i]*(Sum[R[i]]-Sum[L[i]-1]));
        else {
            LL lm=max(L[i],Lmin[i]),rm=min(R[i],Rmin[i]);
            ans=max(ans,a[i]*(Sum[rm]-Sum[lm-1]));
        }
    cout<<ans<<endl;    
    return 0;
}
原文地址:https://www.cnblogs.com/clno1/p/10759002.html