2019南昌邀请赛网络赛 I. Max answer(ST算法+单调栈)

版权声明:本文为博主原创文章,顺手点个赞叭~有问题欢迎指出(*╹▽╹*) https://blog.csdn.net/qq_41117236/article/details/89461110

【题面】

Max answer

【题解】

题意:定义一个区间的价值为区间和*区间最小值,给定一个序列,求子区间的最大价值。

思路:先用ST表维护区间前缀和最大最小值,然后用单调栈跑出以每个值为最小值的最大左边界和右边界,最后对每个值分成负数和正数讨论取可行区间内的最小或最大值。当为负值时,在区间[i,最大右边界]查询最小前缀和,在区间[最大左边界-1,i-1]查询最大前缀和,这样相减能得到最小区间和;当为正值时,在区间[i,最大右边界]查询最大前缀和,在区间[最大左边界-1,i-1]查询最小前缀和,这样相减能得到最大区间和。

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+10;
const ll inf=1e17;
ll a[maxn],sum[maxn];
ll l[maxn],r[maxn];
ll stmx[maxn][23],stmn[maxn][23];
stack <int> stk;
ll askmx(int l,int r)
{
    int k=log2(r-l+1);
    return max(stmx[l][k],stmx[r-(1<<k)+1][k]);
}
ll askmn(int l,int r)
{
    int k=log2(r-l+1);
    return min(stmn[l][k],stmn[r-(1<<k)+1][k]);
}
int main()
{
    int n; scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    for(int i=1;i<=n;i++)
        sum[i]=sum[i-1]+a[i];
    //ST表维护前缀和最大最小值
    for(int i=0;i<=n;i++)
        stmx[i][0]=stmn[i][0]=sum[i];
    for(int j=1;(1<<j)<=n+1;j++){
        for(int i=0;i+(1<<j)-1<=n;i++){
            stmx[i][j]=max(stmx[i][j-1],stmx[i+(1<<(j-1))][j-1]);
            stmn[i][j]=min(stmn[i][j-1],stmn[i+(1<<(j-1))][j-1]);
        }
    }
    //单调栈维护以a[i]为最小值的最左最右端点
    for(int i=1;i<=n;i++){
        while(!stk.empty()&&a[i]<=a[stk.top()])
            stk.pop();
        if(stk.empty()) l[i]=1;
        else l[i]=stk.top()+1;
        stk.push(i);
    }
    while(!stk.empty()) stk.pop();
    for(int i=n;i>=1;i--){
        while(!stk.empty()&&a[i]<=a[stk.top()])
            stk.pop();
        if(stk.empty()) r[i]=n;
        else r[i]=stk.top()-1;
        stk.push(i);
    }
    //查询
    ll ans=-inf;
    for(int i=1;i<=n;i++){
        if(a[i]<0){
            ll R=askmn(i,r[i]);
            ll L=askmx(l[i]-1,i-1);
            ans=max(ans,(R-L)*a[i]);
        }
        else if(a[i]>0){
            ll R=askmx(i,r[i]);
            ll L=askmn(l[i]-1,i-1);
            ans=max(ans,(R-L)*a[i]);
        }
        else ans=max(ans,0ll);
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41117236/article/details/89461110