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; }