Max answer (求区间最小值乘区间和的最大结果,维护左右区间+st求区间最大,最小值)

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

2019武昌赛区网络赛

题意:输入一个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;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值