这题麻烦之处在于有负数,对于每一段连续的正数,我们假设当前最小的数字是a[i],那么所能得到最大的value就是包含i的最大区间且最小值是a[i],直接用单调栈维护每一个数字所统治(以他为最小值)的最大区间范围。
负数的话,对于一个很小的负数,这个区间我们希望他的和越小越好,那么乘起来最大值就会越大,所以我们要想怎么找到包含这个点的和最小的区间,一开始我想用two point ,后来越想越怪。最后我发现一段区间和等于sum[j]-sum[k],那么要求包含a[i]的和最小的区间和就是在i到n之间找一个最小的sum[j],在i-1到0之间找一个最大的sum[k],那么sum[j]-sum[k]就会最小了,虽然a[i]在(k+1)-j这段区间可能不是最小值,但是我们扫过去一定能找到最小值。于是用2个st表维护就行了。
考场上写0-i之间找最大的sum[k]也过了。。。数据可能不是很强
据说还可以cdq分治,,我不会啊。。。
#include<bits/stdc++.h>
#define maxl 500010
using namespace std;
int n,top,lg;
long long ans=0;
long long s[maxl];
long long a[maxl],sum[maxl],dol[maxl],dor[maxl];
long long mini[20][maxl],mx[20][maxl];
map <long long,int> mp;
map <long long,int> :: iterator it;
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i];
top=0;int l=0,r=0;
while(l<=n && r<=n)
{
while(a[l]<=0 && l<=n)
l++;
if(a[l]>0)
{
r=l;
while(a[r+1]>0)
r++;
top=0;s[0]=l-1;
for(int i=l;i<=r;i++)
{
while(top>0 && a[i]<a[s[top]])
{
dor[s[top]]=i;
top--;
}
s[++top]=i;dol[i]=s[top-1];
}
while(top>0)
dor[s[top]]=r+1,top--;
for(int i=l;i<=r;i++)
ans=max(ans,(sum[dor[i]-1]-sum[dol[i]])*a[i]);
}
else r=l;
l=r+1;
}
}
inline void mainwork()
{
int lg=log2(n),t;
for(int i=0;i<=n;i++)
mx[0][i]=mini[0][i]=sum[i];
for(int i=1;i<=lg;i++)
for(int j=0;j<=n;j++)
{
mx[i][j]=max(mx[i-1][j],mx[i-1][j+(1<<(i-1))]);
mini[i][j]=min(mini[i-1][j],mini[i-1][j+(1<<(i-1))]);
}
long long mxx,mii;
for(int i=1;i<=n;i++)
if(a[i]<0)
{
t=log2(i-0+1);
mxx=max(mx[t][0],mx[t][i-(1<<t)+1]);
t=log2(n-i+1);
mii=min(mini[t][i],mini[t][n-(1<<t)+1]);
ans=max((mii-mxx)*a[i],ans);
}
}
inline void print()
{
printf("%lld",ans);
}
int main()
{
prework();
mainwork();
print();
return 0;
}