0%

100048. 美丽塔 II

100048.美丽塔II

题目描述:

给你一个长度为 n 下标从 0 开始的整数数组 maxHeights

你的任务是在坐标轴上建 n 座塔。第 i 座塔的下标为 i ,高度为 heights[i]

如果以下条件满足,我们称这些塔是 美丽 的:

  1. 1 <= heights[i] <= maxHeights[i]
  2. heights 是一个 山状 数组。

如果存在下标 i 满足以下条件,那么我们称数组 heights 是一个 山状 数组:

  • 对于所有 0 < j <= i ,都有 heights[j - 1] <= heights[j]
  • 对于所有 i <= k < n - 1 ,都有 heights[k + 1] <= heights[k]

请你返回满足 美丽塔 要求的方案中,高度和的最大值

数据范围:

$1\le n \le 10^5;1\le maxHeights[i] \le 10^9$

题解:

数据范围比较大,要想使得总高度最大,那么肯定是要取 $heights[i] = maxHeights[i]$ 。但是需要满足左侧递增右侧递减,因此每次碰到一个更低的,都需要修改之前的比他高的。

可以发现是单调栈,因为需要找低的,所以使用单调增栈,每次遇到一个更低的,都要弹出比他高的,然后减去贡献,加上低的贡献。

最后的答案是阶梯状的,每次遇到更低的就弹出一个阶梯,计算阶梯的宽度,宽度就是当前栈顶坐标减去弹出之后的栈顶坐标。最后加上更长的低一些的贡献。

为了简单,可以使用哨兵,在左侧加一个 $-1$ 下标作为哨兵,在反向单调栈中加一个 $n$ 下标作为哨兵。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
auto optimize_cpp_stdio = []()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
class Solution
{
public:
const static int maxn = 1e5 + 10;
const static int maxm = 1e5 + 10;
const int INF = 0x3f3f3f3f;

long long maximumSumOfHeights(vector<int> &maxHeights)
{
int n = maxHeights.size();
// 存下标
int top = -1;
vector<long long> dp1(n);
vector<long long> dp2(n);
vector<int> st(n);
// 前向 单调栈,单调增栈
long long sum = 0;
int pre_index, cur_index = -1;
for (int i = 0; i < n; ++i)
{
while (top >= 0 && maxHeights[st[top]] > maxHeights[i])
{
pre_index = st[top];
cur_index = -1;
--top;
if (top >= 0)
cur_index = st[top];
sum -= 1ll * (pre_index - cur_index) * maxHeights[pre_index];
}
if (top >= 0)
cur_index = st[top];
else
cur_index = -1;
sum += 1ll * (i - cur_index) * maxHeights[i];
st[++top] = i;
dp1[i] = sum;
}

// 反向 单调栈 单调增栈
top = -1;
sum = 0;
cur_index = n;
for (int i = n - 1; i >= 0; --i)
{
while (top >= 0 && maxHeights[st[top]] > maxHeights[i])
{
pre_index = st[top];
cur_index = n;
--top;
if (top >= 0)
cur_index = st[top];
sum -= 1ll * (cur_index - pre_index) * maxHeights[pre_index];
}
if (top >= 0)
cur_index = st[top];
else
cur_index = n;
sum += 1ll * (cur_index - i) * maxHeights[i];
st[++top] = i;
dp2[i] = sum;
}
long long ans = 0;
for (int i = 0; i < n; ++i)
{
ans = max(ans, dp1[i] + dp2[i] - maxHeights[i]);
}
return ans;
}
};