链接: https://ac.nowcoder.com/acm/contest/884/C
题面:
Your are given two sequences
a
1
…
n
,
b
1
…
n
a_{1 \dots n},b_{1 \dots n}
a1…n,b1…n
You need to answer
max
1
≤
l
≤
r
≤
n
{
m
i
n
(
a
l
…
r
)
×
s
u
m
(
b
l
…
r
)
}
\displaystyle \max_{1 \le l \le r \le n} \{min(a_{l \dots r}) \times sum(b_{l \dots r})\}
1≤l≤r≤nmax{min(al…r)×sum(bl…r)}
−
1
e
6
<
a
i
,
b
i
<
1
e
6
-1e6<a_{i},b_{i}<1e6
−1e6<ai,bi<1e6
思路: 用单调栈求出以 a i a_{i} ai为最小值的左右边界,对b数组前缀和,用线段树维护最大值最小值
枚举每个位置p:
若
a
[
p
]
>
0
,
,
要
使
得
区
间
和
尽
可
能
的
大
,
m
a
x
(
s
u
m
[
i
]
,
i
∈
[
p
,
r
]
)
−
m
i
n
(
s
u
m
[
i
]
,
i
∈
[
l
−
1
,
p
−
1
]
)
若a[p]>0,,要使得区间和尽可能的大,max(sum[i],i\in[p,r])-min(sum[i],i\in[l-1,p-1])
若a[p]>0,,要使得区间和尽可能的大,max(sum[i],i∈[p,r])−min(sum[i],i∈[l−1,p−1])
若
a
[
p
]
<
0
,
要
使
得
区
间
和
尽
可
能
的
小
,
m
i
n
(
s
u
m
[
i
]
,
i
∈
[
p
,
r
]
)
−
m
a
x
(
s
u
m
[
i
]
,
i
∈
[
l
−
1
,
p
−
1
]
)
若a[p]<0,要使得区间和尽可能的小,min(sum[i],i\in[p,r])-max(sum[i],i\in[l-1,p-1])
若a[p]<0,要使得区间和尽可能的小,min(sum[i],i∈[p,r])−max(sum[i],i∈[l−1,p−1])
#include<bits/stdc++.h>
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
using namespace std;
typedef long long ll;
const int N=3e6+5;
int a[N],b[N];
ll tree[N<<2][2];
ll sum[N];
int l[N],r[N];
stack<int>s;
void build(int l,int r,int root)
{
if(l==r)
{
tree[root][0]=tree[root][1]=sum[l];
return ;
}
int mid=(l+r)>>1;
build(lson);
build(rson);
tree[root][0]=min(tree[root<<1][0],tree[root<<1|1][0]);
tree[root][1]=max(tree[root<<1][1],tree[root<<1|1][1]);
}
ll querymax(int L,int R,int l,int r,int root)
{
if(L<=l&&R>=r)
{
return tree[root][1];
}
int mid=(l+r)>>1;
ll ans=-(1ll<<60);
if(L<=mid)
ans=max(ans,querymax(L,R,lson));
if(R>mid)
ans=max(ans,querymax(L,R,rson));
return ans;
}
ll querymin(int L,int R,int l,int r,int root)
{
if(L<=l&&R>=r)
{
return tree[root][0];
}
int mid=(l+r)>>1;
ll ans=(1ll<<60);
if(L<=mid)
ans=min(ans,querymin(L,R,lson));
if(R>mid)
ans=min(ans,querymin(L,R,rson));
return ans;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
sum[i]+=sum[i-1]+b[i];
}
build(0,n,1);
for(int i=1;i<=n;i++)
{
while(!s.empty()&&a[s.top()]>=a[i])
s.pop();
if(s.empty())
l[i]=1;
else
l[i]=s.top()+1;
s.push(i);
}
while(!s.empty())s.pop();
for(int i=n;i>0;i--)
{
while(!s.empty()&&a[s.top()]>=a[i])
s.pop();
if(s.empty())
r[i]=n;
else
r[i]=s.top()-1;
s.push(i);
}
ll ans=-(1ll<<60);
for(int i=1;i<=n;i++)
{
if(a[i]==0)
{
ans=max(ans,0ll);
continue;
}
if(a[i]<0)
{
ans=max(1ll*a[i]*(querymin(i,r[i],0,n,1)-querymax(l[i]-1,i-1,0,n,1)),ans);
continue;
}
ans=max(1ll*a[i]*(querymax(i,r[i],0,n,1)-querymin(l[i]-1,i-1,0,n,1)),ans);
}
printf("%lld\n",ans);
return 0;
}