C2. Skyscrapers (hard version)

思路:

显然满足题意的一定是一个单峰序列,于是可以考虑第i个当最高点的时候,左边的最大总和,而这个是可以递推的,因为当m[i]>=m[i-1]的时候第i个可以直接取m[i]加上去,而当m[i] < m[i-1]的时候,要把之前所有大于m[i]的都变成m[i],而之前的部分是单增的,于是可以开个单调栈来维护,复杂度O(n),同理右边的最大总和也可以这么算。

#include <iostream>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <queue>
#include <math.h>
#include <cstdio>
#include <iomanip>
#include <time.h>
#include <bitset>
#include <cmath>
#include <sstream>

#define LL long long
#define INF 0x3f3f3f3f
#define ls nod<<1
#define rs (nod<<1)+1

const double eps = 1e-10;
const int maxn = 5e5 + 10;;
const LL mod = 1e9 + 7;

int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;}
using namespace std;

struct node {
    int val,cnt;
}nd[maxn];

int a[maxn],b[maxn];
LL f[maxn],g[maxn];
int main() {
    int n;
    cin >> n;
    for (int i = 1;i <= n;i++)
        cin >> a[i];
    int cnt = 0;
    for (int i = 1;i <= n;i++) {
        if (a[i] >= a[i-1]) {
            nd[++cnt].val = a[i];
            nd[cnt].cnt = 1;
            f[i] = f[i-1] + a[i];
        }
        else {
            LL sum = 0;
            int num = 0;
            while (cnt >= 1 && nd[cnt].val >= a[i]) {
                sum += nd[cnt].val * 1ll * nd[cnt].cnt;
                num += nd[cnt].cnt;
                cnt--;
            }
            nd[++cnt].val = a[i];
            nd[cnt].cnt = num+1;
            f[i] = f[i-1] - sum + 1ll*nd[cnt].val*nd[cnt].cnt;
        }
    }
    cnt = 0;
    for (int i = n;i >= 1;i--) {
        if (a[i] >= a[i+1]) {
            nd[++cnt].val = a[i];
            nd[cnt].cnt = 1;
            g[i] = g[i+1] + a[i];
        }
        else {
            LL sum = 0;
            int num = 0;
            while (cnt >= 1 && nd[cnt].val >= a[i]) {
                sum += nd[cnt].val * 1ll * nd[cnt].cnt;
                num += nd[cnt].cnt;
                cnt--;
            }
            nd[++cnt].val = a[i];
            nd[cnt].cnt = num+1;
            g[i] = g[i+1] - sum + 1ll*nd[cnt].val*nd[cnt].cnt;
        }
    }
    int id = 1;
    for (int i = 2;i <= n;i++) {
        if (f[i] + g[i] - a[i] > f[id] + g[id] - a[id]) {
            id = i;
        }
    }
    b[id] = a[id];
    for (int i = id-1;i >= 1;i--) {
        b[i] = min(b[i+1],a[i]);
    }
    for (int i = id+1;i <= n;i++) {
        b[i] = min(b[i-1],a[i]);
    }
    for (int i = 1;i <= n;i++) {
        cout << b[i] << " ";
    }
    cout << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/-Ackerman/p/12392361.html