CF 1484E. Skyline Photo
Skyline Photo
题意
有 \(n\) 座建筑排成一排,每座建筑都有 \(h_i\) 高度和 \(b_i\) 美丽度。现在把它们划分成几个连续的区间,每个区间的美丽度为这个区间最矮的建筑的美丽度,问所有区间的美丽度总和最大为多少。
\(1 \le n \le 3 \times 10^5, 1 \le h_i \le n, -10^9 \le b_i \le 10^9\) 。
分析
在从左往右遍历的时候,如果当前建筑的 \(h_i\) 小于前面的建筑,那么在之后不会再次用到前面建筑的高度(当前建筑可能用到)。
可以使用单调栈维护建筑的高度。
用 \(best_t\) 表示栈顶元素为 \(t\) 时,以 \(t\) 为结尾的那一段区间的最大值。
用 \(w_t\) 表示栈顶元素为 \(t\) 时,区间 \([1, t]\) 能划分的最大值。
\(dp_i\) 表示区间 \([1, i]\) 能划分的最大值。
Code
/* 终点是一切概率的结束,也是一切期望的开始 */
#include <bits/stdc++.h>
#define rep(i, x, y) for(int i = x; i <= y; i++)
#define int long long
using namespace std;
const int N = 300010, INF = 0x3f3f3f3f;
int h[N], b[N];
int stk[N], top;
int w[N], best[N];
int dp[N]; // 前i个建筑的最佳划分
void solve ()
{
int n; cin >> n;
rep(i, 1, n) cin >> h[i];
rep(i, 1, n) cin >> b[i];
top = 0;
w[0] = -INF;
rep(i, 1, n)
{
int t = dp[i-1];
while (top && h[stk[top]] > h[i])
{
t = max(t, best[top]);
top -- ;
}
stk[++ top] = i;
best[top] = t;
w[top] = max(w[top - 1], t + b[i]);
dp[i] = w[top];
}
cout << dp[n] << endl;
}
signed main ()
{
cout.tie(0)->sync_with_stdio(0);
// int _; for (cin >> _; _--; )
solve();
return 0;
}