Alice has a magic array. She suggests that the value of a interval is equal to the sum of the values in the interval, multiplied by the smallest value in the interval.
Now she is planning to find the max value of the intervals in her array. Can you help her?
Input
First line contains an integer n(1 \le n \le 5 \times 10 ^5n(1≤n≤5×105).
Second line contains nn integers represent the array a (-10^5 \le a_i \le 10^5)a(−105≤ai≤105).
Output
One line contains an integer represent the answer of the array.
样例输入复制
5 1 2 3 4 5
样例输出复制
36
题意:输入一个n,接下来是n个数,求 任意区间和 *它的区间最小值,使得乘积最大。
思路:和求连续矩形的最大面积那道题十分类似,当然也有不同。我们可以先计算出每一个点朝左,朝右最多能影响到哪个位置。想要直接计算区间和,那么我们就要算出前缀和了。然后我们分开来讨论:
① a[i] >=0 那么也就是说它能影响的区间内的值都是大于等于0的数,因此我们求最大的区间即可。
②.a[i] < 0 我们求的是最大乘积,所以我们就要求最小的区间和,也就是说,从[ i , i 向右最大能影响的位置 ]的最小前缀和 减去 [i 向左最大能影响的位置 , i ]的最大前缀和,,两个相减就是区间的和,即最小区间和。我们用st算法,快速处理区间最大最小值问题。
代码如下:
#include<bits/stdc++.h>
#define ll long long
#define N 500010
#define inf 0x3f3f3f3f
using namespace std;
int n,a[N],l[N],r[N];
int Log[N];
ll Sum[N],Fmax[N][25],Fmin[N][25];
int main()
{
Sum[0]=0,Log[0]=-1,l[1]=1;
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
Sum[i]=Sum[i-1]+a[i]; //前缀和
Log[i]=Log[i>>1]+1; //st算法初始化
Fmax[i][0]=Sum[i],Fmin[i][0]=Sum[i];
if(i>1) //计算向左最多能影响到哪个位置
{
int x=i;
while(x>1&&a[i]<=a[x-1])
x=l[x-1];
l[i]=x;
}
}
r[n]=n;
for(int i=n-1; i>=1; i--) //计算向右最多能影响到哪个位置
{
int x=i;
while(x<n&&a[i]<=a[x+1])
x=r[x+1];
r[i]=x;
}
for(int j=1; j<25; j++) //st算法处理RMQ
for(int i=1; i+(1<<j)-1<=n; i++)
{
Fmax[i][j]=max(Fmax[i][j-1],Fmax[i+(1<<j-1)][j-1]);
Fmin[i][j]=min(Fmin[i][j-1],Fmin[i+(1<<j-1)][j-1]);
}
ll maxx=-1e14;
for(int i=1; i<=n; i++)
{
int x,y;
if(a[i]>=0) //大于等于0
{
x=l[i],y=r[i];
maxx=max(maxx,(ll)a[i]*(Sum[y]-Sum[x-1]));
}
else
{
x=l[i],y=r[i];
int s=Log[y-i+1];
ll mina=min(Fmin[i][s],Fmin[y-(1<<s)+1][s]); //区间最小值
s=Log[i-x+1];
ll maxa=max(Fmax[x][s],Fmax[i-(1<<s)+1][s]); //区间最大值
maxx=max(maxx,(ll)a[i]*(mina-maxa));
}
}
printf("%lld\n",maxx);
return 0;
}