从左往右扫,找到比第i个小的第一个数字,l[i] = l[last] + (i - last) * m[i],用单调栈O(n)维护这个过程,再从右往左扫,同理可以算出r数组,注意一下long long
#include <bits/stdc++.h> using namespace std; const int N = 5000010; int m[N], ans[N]; long long l[N], r[N]; stack < int > s; int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &m[i]); while (!s.empty() && m[s.top()] > m[i]) { s.pop(); } if (s.empty()) l[i] = 1ll * i * m[i]; else l[i] = l[s.top()] + 1ll * (i - s.top()) * m[i]; s.push(i); } while (!s.empty()) s.pop(); for (int i = n; i >= 1; i--) { while (!s.empty() && m[s.top()] > m[i]) { s.pop(); } if (s.empty()) r[i] = 1ll * (n - i + 1) * m[i]; else r[i] = r[s.top()] + 1ll * (s.top() - i) * m[i]; s.push(i); } long long t = 0; int peak = 0; for (int i = 1; i <= n; i++) { long long tot = l[i] + r[i] - m[i]; if (tot > t) peak = i, t = tot; } ans[peak] = m[peak]; for (int i = peak - 1; i >= 1; i--) ans[i] = min(ans[i + 1], m[i]); for (int i = peak + 1; i <= n; i++) ans[i] = min(ans[i - 1], m[i]); for (int i = 1; i <= n; i++) printf("%d ", ans[i]); return 0; }