顺序递增和递减

时间:2017-11-18 21:53:49

标签: algorithm sequence greedy

假设我们已经得到了给定长度n的整数序列。我们想要删除一些元素(可能没有),以便序列在结果中轮流增加和减少。这意味着,每个元素都应该具有相邻元素,既可以更大,也可以比自身小。 例如,1 3 2 7 65 1 4 2 10都是顺序递增和递减的序列。 我们想要删除一些元素来转换我们的序列,但我们也希望最大化剩余元素的总和。因此,例如,从序列2 18 6 7 8 2 10开始,我们要删除6并将其设为2 18 7 8 2 10

我正在寻找解决这个问题的有效方法。上面的例子表明,最天真的贪心算法(删除每个破坏序列的第一个元素)都不会起作用 - 它会删除7而不是6,这不会最大化元素之和剩下。 任何想法如何有效地解决(可能O(n) or O(n log n))正确?

1 个答案:

答案 0 :(得分:0)

对于索引为i的序列的每个元素,我们将计算F(i, high)F(i, low),其中F(i, high)等于子序列的最大总和,其中所需特征结束使用i - 元素,此元素是“高峰”。 (我将主要解释“高”部分,“低”部分可以类似地完成)。我们可以使用以下关系计算这些函数:

enter image description here

答案在所有F(i, high)F(i, low)值中最大。

这为我们提供了一个相当简单的动态编程解决方案,其时间复杂度为O(n^2)。但我们可以走得更远。

我们可以优化max(F(j,low))部分的计算。我们需要做的是找到先前计算的F(j, low)中具有a[j] < a[i]条件的最大值。这可以使用segment trees完成。

首先,我们将“挤压”我们的初始序列。只有在计算总和时,我们才需要元素a[i]的实际值。但在检查a[j]是否小于a[i]时,我们只需要元素的相对顺序。因此,我们将每个元素映射到排序元素数组中的索引,而不重复。例如,序列a = 2 18 6 7 8 2 10将转换为b = 0 5 1 2 3 0 4。这可以在O(n*log(n))中完成。

b的最大元素将小于n,因此,我们可以在细分[0, n]上构建细分树,每个节点都包含细分中的最大总和(我们需要两个分段树,相应地为“高”和“低”部分)。现在让我们描述算法的步骤i

  1. 使用“低”细分树树找到细分max_low上的最大金额[0, b[i]-1](最初树的所有节点都包含零)。
  2. F(i, high)等于max_low + a[i]
  3. 使用“高”细分树在细分max_high上找到最大金额[b[i]+1, n]
  4. F(i, low)等于max_high + a[i]
  5. 更新“高”细分树的[b[i], b[i]]段,F(i, high)值重新计算父节点的最大值(以及[b[i], b[i]]节点本身)。
  6. 对“低”细分树和F(i, low)执行相同操作。
  7. 复杂性分析:b序列计算为O(n*log(n))。细分树最大/更新操作的复杂度为O(log(n)),其中有O(n)个。该算法的总体复杂度为O(n*log(n))