(南昌网络赛)Max answer

  •  11.34%
  •  3000ms
  •  262144K

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)

Output

One line contains an integer represent the answer of the array.

样例输入复制

5
1 2 3 4 5

样例输出复制

36

题意: 给一个数组,找出任意一个区间的和*这个区间最小的数的最大值

            1  2  3  4  5           区间 :4 ~ 5 ,最小值 :4  ,ans = 4*9=36

            1  -1  -2  -3  -4     区间 : -1 ~ -4   最小值 :-4 ,ans = 40

题解:正负数分开搞;

           以某个正数为最小值:用单调栈搞

           以某个负数为最小值:用最小子段和搞,记录起始和终止点,用线段树查出该区间的最小值(可能有多个相同的最小子段和区间,要每个都求出来)。

#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<bitset>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define eps (1e-8)
#define MAX 0x3f3f3f3f
#define u_max 1844674407370955161
#define l_max 9223372036854775807
#define i_max 2147483647
#define re register
#define pushup() tree[rt]=max(tree[rt<<1],tree[rt<<1|1])
#define nth(k,n) nth_element(a,a+k,a+n);  // 将 第K大的放在k位
#define ko() for(int i=2;i<=n;i++) s=(s+k)%i // 约瑟夫
#define ok() v.erase(unique(v.begin(),v.end()),v.end()) // 排序,离散化
using namespace std;

inline int read(){
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' & c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}

typedef long long ll;
const double pi = atan(1.)*4.;
const int M=1e3+5;
const int N=1e6+5;
int n;
ll a[N],p1=1,p2=1,p3=1,p4=1,x=0,y=0;
ll ans1=-l_max,ans2=l_max;
ll tree[N<<2];
ll sum[N];
int l[N],r[N];

void sett(int l,int r,int rt){      // 最小值线段树
    if(l==r){
        tree[rt]=a[l];
        return ;
    }
    int mid=l+r>>1;
    sett(l,mid,rt<<1);
    sett(mid+1,r,rt<<1|1);
    tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
}


ll findd(int a,int b,int l,int r,int rt){
    if(a<=l&&b>=r){
        return tree[rt];
    }
    int mid=l+r>>1;
    ll ans=l_max;
    if(a<=mid)
        ans=min(ans,findd(a,b,l,mid,rt<<1));
    if(b>mid)
        ans=min(ans,findd(a,b,mid+1,r,rt<<1|1));
    return ans;
}
struct fun{
    int l,r;
}f[N],g[N];          // f 保存最大子段和相同的区间, g 保存最小子段和相同的区间
void fun1(){         //  求最大子段和
    ll sum=0;
    int d=1;
    for(int i=1;i<=n;i++){
        sum+=a[i];
        if(sum>ans1){
            ans1=sum;
            p1=d;
            p2=i;
        }
        if(sum<0){
            sum=0;
            d=i+1;
        }
    }
    d=1; sum=0;
    for(int i=1;i<=n;i++){
        sum+=a[i];
        if(sum==ans1){
            p1=d;
            p2=i;
            f[x].l=p1;
            f[x++].r=p2;
        }
        if(sum<0){
            sum=0;
            d=i+1;
        }
    }
}

void fun2(){          // 求最小子段和
    ll sum=0;
    int d=1;
    for(int i=1;i<=n;i++){
        sum+=a[i];
        if(sum<ans2){
            ans2=sum;
            p3=d;
            p4=i;
        }
        if(sum>=0){
            sum=0;
            d=i+1;
        }
    }

    d=1; sum=0;
    for(int i=1;i<=n;i++){
        sum+=a[i];
        //printf("sum == %lld\n",sum);
        if(sum==ans2){
              //  printf("YES\n");
            p3=d;
            p4=i;
            g[y].l=p3;
            g[y++].r=p4;
        }
        if(sum>=0){
            sum=0;
            d=i+1;
        }
    }
}
stack<int>s1,s2;
int main(){
    scanf("%d",&n);
    sum[0]=0;
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        sum[i]=sum[i-1]+a[i];
    }

    for(int i=1;i<=n;i++){          // 左边第一个比它小的
        while(s1.size()&&a[s1.top()]>=a[i]) s1.pop();
        if(s1.empty()) l[i]=0;
        else l[i]=s1.top();
        s1.push(i);
    }

    for(int i=n;i>=1;i--){          // 右边第一个比它小的
        while(s2.size()&&a[s2.top()]>=a[i]) s2.pop();
        if(s2.empty()) r[i]=n+1;
        else r[i]=s2.top();
        s2.push(i);
    }

    ll ans=-1*1e9;
    for(int i=1;i<=n;i++){       
        ll cut=a[i]*(sum[r[i]-1]-sum[l[i]]);
        ans=max(ans,cut);
    }

    fun1();
    fun2();

    sett(1,n,1);
    ll cut1=-l_max,cut2=l_max;
    for(int i=0;i<x;i++){
        cut1=max(cut1,findd(f[i].l,f[i].r,1,n,1));
    }
    for(int i=0;i<y;i++){
        cut2=min(cut2,findd(g[i].l,g[i].r,1,n,1));
    }
    printf("%lld\n",max(ans,max(cut1*ans1,cut2*ans2)));
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值