📌  相关文章
📜  最大化数组中索引 K 处的元素,其总和为 M,相邻元素之间的差值至多为 1(1)

📅  最后修改于: 2023-12-03 15:10:35.156000             🧑  作者: Mango

最大化数组中索引 K 处的元素,其总和为 M,相邻元素之间的差值至多为 1

这个问题可以使用动态规划来解决。具体来说,我们可以定义 $dp[i][j]$ 为目前已经处理了前 $i$ 个元素,且将第 $i$ 个元素设为 $j$ 的最大值。具体转移方程如下:

$$ dp[i][j] = \max_{j - 1 \leq k \leq j + 1} dp[i - 1][k] + A[i][j] $$

其中 $A[i][j]$ 表示原数组第 $i$ 个位置上面的值是 $j$ 时对应的权值。容易注意到,这个转移方程的时间复杂度是 $\mathcal{O}(n k)$ 的,无法通过本题。

不过可以发现,上面的转移方程存在一定的单调性,因此我们可以使用单调队列来优化转移过程。具体来说,对于一个位置 $i$,设 $q_j$ 表示以转移 $dp[i-1][j]$ 时对应的最优选择 $k$ 为队列顶部元素,此时在推 $dp[i][j]$ 的时候可以直接取 $q_j$(这是单调队列优化的关键,有没有!!!)。具体细节可以看代码。

实现代码如下:

def solve(n: int, k: int, m: int):
    a = [[0] * (k + 2) for _ in range(n + 1)]
    for i in range(1, n + 1):
        l, r, val = map(int, input().split())
        for j in range(l, r + 1):
            a[i][j] = val

    dp = [[0] * (k + 2) for _ in range(n + 1)]
    for j in range(1, k + 1):
        dp[1][j] = a[1][j]

    for i in range(2, n + 1):
        q = []
        for j in range(1, k + 1):
            while q and q[0][0] + 1 < j:
                q.pop(0)
            dp[i][j] = dp[i - 1][q[0][1]] + a[i][j]
            if q:
                dp[i][j] = max(dp[i][j], dp[i - 1][q[-1][1]] + a[i][j])
            while q and dp[i - 1][j - 1] - a[i][j - 1] > dp[i - 1][q[-1][1]] - a[i][q[-1][1]]:
                q.pop()
            q.append((j - 1, j))
        if m in dp[i]:
            return i
    return -1

时间复杂度 $\mathcal{O}(n k)$,可以通过本题。