【问题标题】:How to solve Twisty Movement from Codeforces?如何从 Codeforces 解决 Twisty Movement?
【发布时间】:2018-06-06 10:09:41
【问题描述】:

我已经阅读了社论,但它很短,并且声称我不明白为什么它是真的。为什么等于找到1*2*1*2*的最长子序列?有人可以逐步解释解决方案并在每一步证明索赔的合理性吗? http://codeforces.com/contest/934/problem/C

这是社论中的“解决方案”,但正如我所说,它很短,我不明白。希望有人可以一步一步地指导我解决问题,而不是像这里的解决方案那样。谢谢。

由于1 ≤ ai ≤ 2,相当于找到了一个最长的子序列如 1 * 2 * 1 * 2 * 。通过一个简单的动态规划,我们可以在 O(n)O(n2) 时间。可以在模型中看到O(n2)解决方案 下面的解决方案。这里我们介绍一种 O(n) 方法:由于 子序列可以分成4部分(11...22...11...22...),我们 可以设置dp[i][j](i = 1...n, j = 0..3)为最长子序列 a[1...i] 与第一个 j 部分。

【问题讨论】:

    标签: algorithm dynamic-programming


    【解决方案1】:

    我也认为引用的解释不是很清楚。这是另一个镜头。

    您可以折叠原始数组

    1 1 2 2 2 1 1 2 2 1
    

    放入加权数组

    2 3 2 2 1
    ^ ^ ^ ^ ^
    1 2 1 2 1
    

    其中顶部的数字表示原始数组中连续重复值的长度。

    我们可以说服自己

    1. 最佳翻转不会“打断”任何连续序列。
    2. 最佳翻转以不同的值开始和结束(即以 1 开始并以 2 结束,或以 2 开始并以 1 结束)。

    因此,加权数组包含足够的信息来解决问题。我们想要翻转加权数组 s.t. 的连续切片。与某个连续单调序列相关的权重之和被最大化。

    具体来说,我们希望以这样一种方式执行翻转,使某些连续的单调序列112122211221 具有最大权重。

    使用动态编程实现此目的的一种方法是创建 4 个辅助数组。

    1. A[i] : i 右边任意 1 的最大权重。
    2. B[i] : i 左边任意 1 的最大权重。
    3. C[i] : i 右边任意 2 的最大权重。
    4. D[i] : i 左边任意 2 的最大权重。

    假设如果A,B,C,D中的任何一个被越界访问,则返回值为0

    我们初始化x = 0 并使用权重W = [2, 3, 2, 2, 1] 遍历数组Arr = [1, 2, 1, 2, 1]。在每个索引i,我们有 2 个案例:

    1. Arr[i:i+2] == 1 2。在这种情况下,我们设置
      • x = max(x, W[i] + W[i+1] + C[i+1], W[i] + W[i+1] + B[i-1]).
    2. Arr[i:i+2] == 2 1。在这种情况下,我们设置
      • x = max(x, W[i] + W[i+1] + A[i+1], W[i] + W[i+1] + D[i-1])

    生成的x 就是我们的答案。这是一个 O(N) 的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-04
      • 2014-09-07
      • 1970-01-01
      • 2021-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多