https://ac.nowcoder.com/acm/contest/884/C
----------------------------------------------------------------
和南昌网络赛Max Answer一样,些许变化。
这里讲了线段树具体求区间最小子段和https://blog.csdn.net/gml1999/article/details/89682326、
---------------------------------------------------------------------------------------------------------------------------
题意:给你a.b两个数组,让你求max{min a(l,r)*sum b(l,r)} 1<l<r<n;
求最大值:连续区间和*区间最小值
题解:
求最小值时用单调栈求该值左边第一个小的与右边第一个小的来枚举区间
当a[i]负数时:需要求b数组区间内最小连续子段和;(只有区间内子段和为负时,才会让乘积最大化)
当a[i]正数时:需要求b数组区间内最大连续子弹和;(因为b数组区间内有正有负)
这里用线段树操作找区间和最小/最大:(线段树操作基于a[i]下标的x找)
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
#include<stack>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=3e6+10;
typedef long long ll;
const ll iinf=0x3f3f3f3f3f3f3f3f;
int a[maxn];
int b[maxn];
int l[maxn];
int r[maxn];
stack<int> s;
ll sum[maxn*4+1];// 和
ll lmin[maxn*4+1];//当 x 为负数时 找以x为左端点的右区间最小和
ll rmin[maxn*4+1];//同理 找以x为右端点的左区间最小和
ll lmax[maxn*4+1];//当x为正数时,同理
ll rmax[maxn*4+1];
ll pes[maxn];//前缀和 快速操作求区间和O(1);
void pushup(int x){
sum[x]=sum[x<<1]+sum[x<<1|1];
lmin[x]=min(lmin[x<<1],sum[x<<1]+lmin[x<<1|1]);//紧靠以x为左端点的左儿子 和 以x为左端点左儿子区间和+右儿子紧靠x的区间 比较
rmin[x]=min(sum[x<<1|1]+rmin[x<<1],rmin[x<<1|1]);//紧靠以x为右端点的右儿子 和 以x为右端点的右儿子区间和和+左儿子紧靠x的区间比较
lmax[x]=max(lmax[x<<1],sum[x<<1]+lmax[x<<1|1]);//同理
rmax[x]=max(sum[x<<1|1]+rmax[x<<1],rmax[x<<1|1]);
}
void build(int l,int r,int p){
if(l==r){
rmax[p]=lmax[p]=sum[p]=lmin[p]=rmin[p]=b[l];
return ;
}
int mid=(l+r)/2;
build(l,mid,p<<1);
build(mid+1,r,p<<1|1);
pushup(p);
}
int x;//全程是以这个点为端点找左右
ll quertminL(int L,int R,int l,int r,int p){//找[x,R];固定x为L 紧靠x的右区间
if(L<=l&&r<=R){
return pes[l-1]-pes[x-1]+lmin[p];
}
int mid=(l+r)/2;
ll ans=iinf;
if(L<=mid){
ans=min(ans,quertminL(L,R,l,mid,p<<1));
}
if(R>mid){
ans=min(ans,quertminL(L,R,mid+1,r,p<<1|1));
}
return ans;
}
ll quertminR(int L,int R,int l,int r,int p){//[L,x];固定x为R 紧靠x的左区间
if(L<=l&&r<=R){
return pes[x]-pes[r]+rmin[p];
}
int mid=(l+r)/2;
ll ans=iinf;
if(L<=mid){
ans=min(ans,quertminR(L,R,l,mid,p<<1));
}
if(R>mid){
ans=min(ans,quertminR(L,R,mid+1,r,p<<1|1));
}
return ans;
}
ll quertmaxL(int L,int R,int l,int r,int p){//找[x,R];固定x为L 紧靠x的右区间
if(L<=l&&r<=R){
return pes[l-1]-pes[x-1]+lmax[p];
}
int mid=(l+r)/2;
ll ans=-iinf;
if(L<=mid){
ans=max(ans,quertmaxL(L,R,l,mid,p<<1));
}
if(R>mid){
ans=max(ans,quertmaxL(L,R,mid+1,r,p<<1|1));
}
return ans;
}
ll quertmaxR(int L,int R,int l,int r,int p){//[L,x];固定x为R 紧靠x的左区间
if(L<=l&&r<=R){
return pes[x]-pes[r]+rmax[p];
}
int mid=(l+r)/2;
ll ans=-iinf;
if(L<=mid){
ans=max(ans,quertmaxR(L,R,l,mid,p<<1));
}
if(R>mid){
ans=max(ans,quertmaxR(L,R,mid+1,r,p<<1|1));
}
return ans;
}
int main(){
std::ios::sync_with_stdio(false);
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
pes[i]=b[i]+pes[i-1];//前缀和
}
build(1,n,1);
while(!s.empty()) s.pop();
for(int i=1;i<=n;i++){
while(s.size()&&a[s.top()]>=a[i]) s.pop();
if(s.empty()) l[i]=0;
else l[i]=s.top();
s.push(i);
}
while(!s.empty()) s.pop();
for(int i=n;i>=1;i--){
while(s.size()&&a[s.top()]>=a[i]) s.pop();
if(s.empty()) r[i]=n+1;
else r[i]=s.top();
s.push(i);
}
ll ans=-iinf;//注意
for(int i=1;i<=n;i++){
int k=a[i];
int L=l[i]+1;
int R=r[i]-1;
x=i;//
if(L==R){
ans=max(ans,(ll)(a[i]*b[i]));
continue;
}
if(k>0){
ans=max(ans,(quertmaxL(i,R,1,n,1)+quertmaxR(L,i,1,n,1)-b[i])*k);
}else if(k<0){
ans=max(ans,(quertminL(i,R,1,n,1)+quertminR(L,i,1,n,1)-b[i])*k);
}else if(k==0){
ans=max(ans,0ll);
}
}
cout<<ans<<endl;
}