链接:https://ac.nowcoder.com/acm/contest/884/C
来源:牛客网
题意很好懂。
【做法】
从a数组中枚举以当前a[i]为最小值时能左右包括的最大范围,这是单调栈的常用做法了。维护递增的栈就可以了。
预处理b的前缀和用线段树维护区间最大值、最小值。
准备工作做完后开始求答案,枚举a[i],若a[i]>0 ,那就从i到r[i]区间内找最大的前缀和rsum,从l[i]~i-1找最小的前缀和lsum,l[i]和r[i]是之前单调栈预处理得到的i位置能左右扩展的最大区间。
【注】:这个题十分卡常,我这份代码是有时能A,有时不能A。。。
赛后交了5发A的。赛时没过。。。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e6+1;
int n;
ll a[N],stmax[N*4],stmin[N*4];
int l[N],r[N],b[N],indexst[N],tail;
void up(int id,int l,int r)
{
if(l==r)
{
stmax[id]=a[l];
stmin[id]=a[l];
return ;
}
int mid=l+r>>1;
up(id<<1,l,mid);
up(id<<1|1,mid+1,r);
stmax[id]=max(stmax[id<<1],stmax[id<<1|1]);
stmin[id]=min(stmin[id<<1],stmin[id<<1|1]);
}
void init()
{
for(int i=1;i<=n;i++) a[i]=a[i-1]+a[i];
up(1,1,n);
for(int i=1;i<=n;i++)
{
while(tail>1&&b[i]<=b[indexst[tail]]) --tail;
if(tail==0) l[i]=1;
else
l[i]=indexst[tail]+1;
indexst[++tail]=i;
}
tail=0;
for(int i=n;i>=1;i--)
{
while(tail>0&&b[i]<=b[indexst[tail]]) --tail;
if(tail==0){
r[i]=n;
}
else
r[i]=indexst[tail]-1;
indexst[++tail]=i;
}
}
ll querymax(int id,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr) return stmax[id];
int mid=l+r>>1;
ll ans=-0x3f3f3f3f3f3f3f3f;
if(ql<=mid) ans=max(ans,1ll*querymax(id<<1,l,mid,ql,qr));
if(qr>mid) ans=max(ans,1ll*querymax(id<<1|1,mid+1,r,ql,qr));
return ans;
}
ll querymin(int id,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr) return stmin[id];
int mid=l+r>>1;
ll ans=0x3f3f3f3f3f3f3f3f;
//stmin[id]=ans;
if(ql<=mid) ans=min(ans,1ll*querymin(id<<1,l,mid,ql,qr));
if(qr>mid) ans=min(ans,1ll*querymin(id<<1|1,mid+1,r,ql,qr));
return ans;
}
ll rsum,lsum;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&b[i]);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
if(n==1){
printf("%lld\n",a[1]*b[1]);
return 0;
}
init();
ll ans=-0x3f3f3f3f3f3f3f3f;
for(int i=1;i<=n;i++)
{
if(b[i]<0)
{
rsum=querymin(1,1,n,i,r[i]);
int ql=max(1,l[i]-1),qr=max(i-1,1);
lsum=querymax(1,1,n,ql,qr);
ans=max(ans,(rsum-lsum)*b[i]);
}
else if(b[i]>0)
{
rsum=querymax(1,1,n,i,r[i]);
int ql=max(1,l[i]-1),qr=max(i-1,1);
lsum=querymin(1,1,n,ql,qr);
ans=max(ans,(rsum-lsum)*b[i]);
}
else ans=ans>0?ans:0;
}
printf("%lld\n",ans);
return 0;
}