2019南昌网络赛【 Max answer】【单调栈+ST表】

一开始的思路只是单调栈+前缀和就好了,后来发现当最小值为负数的时候并不能找到最优解。
比如-3 7 -1 -2 -1这种情况
正确的想法是对前缀和建立st表,还是单调队列求最近的小于x的编号。
当最小值<0的时候,应该求【i, R[i]】范围内的前缀和的最小 减去 【L[i], i-1】范围内前缀和最大。
反之求【i, R[i]】范围内的前缀和的最大 减去 【L[i], i-1】范围内前缀和最小。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e5+5;
int Case = 1;
int n, m;
ll cc[maxn];
ll L[maxn], R[maxn];
ll stmi[maxn][30], stmx[maxn][30], pre[maxn];
void initst() {
    for(int i = 1; i <= n; i++) pre[i] = pre[i-1] + cc[i];
    for(int i = 0; i <= n; i++) stmi[i][0] = stmx[i][0] = pre[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]);
            stmi[i][j] = min(stmi[i][j-1], stmi[i+(1<<(j-1))][j-1]);
        }
    }
}
ll askmx(int l, int r) {
    int k = log2(r-l+1);
    return max(stmx[l][k], stmx[r-(1<<k)+1][k]);
}
ll askmi(int l, int r) {
    int k = log2(r-l+1);
    return min(stmi[l][k], stmi[r-(1<<k)+1][k]);
}
void solve() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%lld", &cc[i]);
    }
    initst();
    stack<int>st;
    for(int i = 1; i <= n; i++) {
        while(st.size() && cc[st.top()] >= cc[i]) {
            st.pop();
        }
        if(st.empty()) L[i] = 1;
        else L[i] = st.top() + 1;
        st.push(i);
    }
    while(!st.empty()) st.pop();
    for(int i = n; i >= 1; i--) {
        while(st.size() && cc[st.top()] >= cc[i]) {
            st.pop();
        }
        if(st.empty()) R[i] = n;
        else R[i] = st.top()-1;
        st.push(i);
    }
    ll res = -1e18;
    for(int i = 1; i <= n; i++) {
        if(cc[i] < 0) {
            ll r = askmi(i, R[i]);
            ll l = askmx(L[i]-1, i-1);
            res = max(res, (r-l)*cc[i]);
        }
        else {
            ll r = askmx(i, R[i]);
            ll l = askmi(L[i]-1, i-1);
            res = max(res, (r-l)*cc[i]);
        }
    }
    printf("%lld\n", res);
    return;
}
int main() {
    //g++ -std=c++11 -o2 1.cpp -o f && ./f < in.txt
    //ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt","w",stdout);
#endif
while(Case--) {
    solve();
    }
return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39921637/article/details/89462797
今日推荐