鏈接: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;
}