Solution
每次遇到这种比较复杂的问题的时候,可以先从比较直观的暴力方法去考虑再去思考如何优化。
比如这道题,我们比较容易的想到的是的dp转移。
定义:
: 到第 个建筑物的最大美丽值。
: 到 之间最矮的建筑物的美丽值,即。
为了降低复杂度,DP存在很多种优化方式,而这道题需要用到单调队列优化。
仔细观察,我们可以发现 是单调递增的, 是固定的。
利用单调栈维护单调递减的 数组对应的下标,对于 , 我们可以找到左侧最近的 , 使得 ,此时 有两种可能:
- 将 和 放入到一张照片,此时答案为
- 将 放入到一张照片,
O(NlogN)
#include <bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pb push_back #define lowbit(x) ((x) & -(x)) using namespace std; using ll = long long; using ull = unsigned long long; using pii = pair<int, int>; constexpr double eps = 1e-8; constexpr int NINF = 0xc0c0c0c0; constexpr int INF = 0x3f3f3f3f; constexpr ll LINF = 0x3f3f3f3f3f3f3f3f; constexpr ll LNINF = 0xc0c0c0c0c0c0c0c0; constexpr ll mod = 1e9 + 7; constexpr ll N = 3e5 + 5; int n, h[N], b[N], l[N]; ll f[N]; #define ls (p << 1) #define rs (ls | 1) #define tm ((tl + tr) >> 1) ll mx[N << 2]; void up(int p) { mx[p] = max(mx[ls], mx[rs]); } void modify(int p, int tl, int tr, int pos, ll v) { if (tl == tr) { mx[p] = v; } else { if (tm >= pos) modify(ls, tl, tm, pos, v); else modify(rs, tm + 1, tr, pos, v); up(p); } } ll query(int p, int tl, int tr, int l, int r) { if (r < l) { return 0; } else if (l <= tl && tr <= r) { return mx[p]; } else { ll ans = LLONG_MIN; if (tm >= l) ans = max(ans, query(ls, tl, tm, l, r)); if (tm < r) ans = max(ans, query(rs, tm + 1, tr, l, r)); return ans; } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n; for (int i = 1; i <= n; i++) cin >> h[i]; for (int i = 1; i <= n; i++) cin >> b[i]; vector<int> stk; for (int i = 1; i <= n; i++) { while (!stk.empty() && h[stk.back()] > h[i]) { stk.pop_back(); } if (!stk.empty()) l[i] = stk.back(); stk.push_back(i); } memset(mx, sizeof(mx), 0xc0); f[0] = LNINF; modify(1, 0, n, 0, 0); for (int i = 1; i <= n; i++) { f[i] = max(f[l[i]], query(1, 0, n, l[i], i - 1) + b[i]); modify(1, 0, n, i, f[i]); } cout << f[n] << '\n'; return 0; }
Code O(NlogN)
#include <bits/stdc++.h> #define fi first #define se second #define mp make_pair #define lowbit(x) ((x) & -(x)) using namespace std; using ll = long long; using ull = unsigned long long; using pii = pair<int, int>; constexpr double eps = 1e-8; constexpr int NINF = 0xc0c0c0c0; constexpr int INF = 0x3f3f3f3f; constexpr ll mod = 1e9 + 7; constexpr ll N = 1e6 + 5; int n, h[N], b[N], stk[N]; ll stk_v[N], f[N]; bool in_queue[N]; priority_queue<pair<ll, int>> pq; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n; for (int i = 1; i <= n; i++) cin >> h[i]; for (int i = 1; i <= n; i++) cin >> b[i]; int top = 0; for (int i = 1; i <= n; i++) { ll now = f[i - 1]; while (top > 0 && h[i] < h[stk[top]]) { now = max(now, stk_v[top]); in_queue[stk[top]] = false; top--; } stk[++top] = i; stk_v[top] = now; in_queue[i] = true; pq.push(make_pair(now + b[i], i)); while (!in_queue[pq.top().second]) pq.pop(); f[i] = pq.top().first; } cout << f[n] << '\n'; return 0; }
O(N)
#include <bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pb push_back #define ls (p << 1) #define rs (ls | 1) #define tm ((tl + tr) >> 1) #define lowbit(x) ((x) & -(x)) using namespace std; using ll = long long; using ull = unsigned long long; using pii = pair<int, int>; constexpr double eps = 1e-8; constexpr int NINF = 0xc0c0c0c0; constexpr int INF = 0x3f3f3f3f; constexpr ll LNINF = 0xc0c0c0c0c0c0c0c0; constexpr ll LINF = 0x3f3f3f3f3f3f3f3f; constexpr ll mod = 1e9 + 7; constexpr ll N = 1e6 + 5; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; cin >> n; vector<int> h(n), b(n); for (auto &i : h) cin >> i; for (auto &i : b) cin >> i; vector<ll> f(n); stack<int> stk; stack<ll> stkdp, stkmax; for (int i = 0; i < n; i++) { ll mx = i == 0 ? 0 : f[i - 1]; while (!stk.empty() && h[stk.top()] > h[i]) { mx = max(mx, stkdp.top()); stk.pop(); stkdp.pop(); stkmax.pop(); } stkdp.push(mx); if (stkmax.empty()) { stkmax.push(mx + b[i]); } else { stkmax.push(max(stkmax.top(), mx + b[i])); } f[i] = stkmax.top(); stk.push(i); } cout << f[n - 1] << '\n'; return 0; }