如何用Codeforces解决Twisty运动?

时间:2018-06-06 10:09:41

标签: algorithm dynamic-programming

我读过这篇社论,但它很短,声称我不明白为什么这是真的。为什么它等同于找到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] jGetPathHandler()部分。

1 个答案:

答案 0 :(得分:0)

我也认为引用的解释不是很清楚。这是另一种看法。

您可以折叠原始数组

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结束)。
  3. 因此,加权数组包含足够的信息来解决问题。我们想要翻转加权数组s.t.的连续切片。与某些连续单调序列相关的权重之和最大化。

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

    动态编程的一种方法是创建4个辅助数组。

    1. A[i]:i右边任意1的最大权重。
    2. B[i]:i左边任意1的最大重量。
    3. C[i]:i右边任意2的最大权重。
    4. D[i]:i左边任意2的最大权重。
    5. 假设如果访问A,B,C,D中的任何一个超出范围,则返回的值为0

      我们初始化x = 0并通过权重Arr = [1, 2, 1, 2, 1]的数组W = [2, 3, 2, 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])
      3. 结果x是我们的答案。这是一个O(N)解决方案。