【问题标题】:Maximum "divide" operations on an array数组上的最大“除法”操作
【发布时间】:2015-02-23 03:14:42
【问题描述】:

给定一个由n 正整数组成的数组a[1], a[2], ..., a[n]m 好的整数对(i 1, j1), (i2, j2), ..., (im, jm) 其中 1 ≤ ik k ≤ n , n

编辑:每个好的对 (ik, jk) 满足以下条件:ik + jk 是奇数且 1 ≤ ik 

在一个操作中,您可以执行一系列操作: 取其中一对 (ik, jk) 和一些整数 v (v > 1) ,这将两个数字 a[ik]a[jk]divide v 两个数字。

确定您可以在给定数组上按顺序执行的最大个操作数。请注意,一对可能在所述操作中多次使用。

我的方法:

我首先对数组的每个数字进行质因数分解。 给定一对好对 (ik,jk),我们可以将两个数 A[ik]A[jk] 除以它们的共同素数幂即如果A[ik]=2^5 * 3^4A[jk]=2^3 * 3^7 那么我们可以将它们都除以 23 次 并除以 3 4 次。操作的数量增加了最小的公素数,即 7

然后可以将操作总数视为所有给定好的对的所有公共素数的总和。

但是,对于以下 测试用例,我的代码失败

N=10 

M=9 

A[]=67108864 8 2 131072 268435456 256 16384 128 8 128 

Good Pairs :

4 9

5 10 

6 9 

9 10 

1 4 

3 8 

8 9 

1 2 

4 5

数组的每个元素都是 2 的不同幂。

根据2的幂,数组可以写成:

B[]= 26 3 1 17 28 8 14 7 3 7 //A[i] = 2^B[i]

选择每个 好对 并减去 2 的共同幂,我对每个好对的答案进展为:

26 3 1 14 28 8 14 7 0 7 ans 3

26 3 1 14 21 8 14 7 0 0 ans 10

26 3 1 14 21 8 14 7 0 0 ans 10

26 3 1 14 21 8 14 7 0 0 ans 10

12 3 1 0 21 8 14 7 0 0 ans 24

12 3 0 0 21 8 14 6 0 0 ans 25

12 3 0 0 21 8 14 6 0 0 ans 25

9 0 0 0 21 8 14 6 0 0 ans 28

9 0 0 0 21 8 14 6 0 0 ans 28

处理好每一对,我的代码给出的答案是 28

但是正确答案是 31。我需要帮助来理解输出是如何变成 31 的以及解决这个问题的方法。

PS:问题是codeforces Div2 Round 284的问题E。

问题链接: http://codeforces.com/contest/499/problem/E

【问题讨论】:

  • 我认为操作顺序很重要。这是一个示例,a = [2, 4, 4, 2],而好的对 = [(1, 2), (3, 4), (2, 3)]。如果您按给定顺序应用对,您将获得 3 次操作。但是,如果您先申请 (2, 3),您将只能进行 2 次操作。

标签: arrays algorithm prime-factoring number-theory


【解决方案1】:

这个问题可以通过在下图中找到最大值matching 来解决。对于每个数组值 x,对于具有多重性的 x 的每个素因子,创建一个新顶点。例如,如果 x = 12,那么我们创建两个 2 顶点和一个 3 顶点。在与数组值的相同素数因子相对应的顶点对之间制作边,从而形成一对。例如,在输入上

A  B  C  # array indexes
8 12 18  # array
A B      # good pairs
B C,

图有顶点

{A2a, A2b, A2c, B2a, B2b, B3, C2, C3a, C3b}

和边缘

{{A2a, B2a}, {A2a, B2b}, {A2b, B2a}, {A2b, B2b}, {A2c, B2a}, {A2c, B2b},
 {B2a, C2}, {B2b, C2},
 {B3, C3a}, {B3, C3b}}.

{A2c, B2a} 为例,其含义是我们将标记为AB 的数组条目除以2。操作顺序无关紧要。

现在,有一些算法可以找到最大的一般匹配,但它们很复杂,我很惊讶编程竞赛会使用它们。事实证明,您遗漏了一个重要的约束,即好的对总和为奇数,这保证了图将是二分的,因此适用于更简单的算法。根据实例的外观,从二分匹配切换到最大流也可能是有利可图的,例如,这允许 2 因子的五个顶点和六个边 AB 是用三个容量单位的两个顶点和一个边替换。

【讨论】:

  • 对不起。实际上,我没有将索引总和的那部分添加为奇数的唯一原因是因为我认为这无关紧要。我的错。我理解了图的创建,但是好对和奇数如何确保图是二分的?
  • @user3918495 如果i, ji, kj, k 都是很好的配对,那么i + ji + kj + k 都是奇数,它们的总和也一样,@ 987654338@,这是一个矛盾。这个论点推广到所有奇数循环。
  • @user3918495 一个不那么愚蠢的证明是将偶数索引放在一个部分,将奇数索引放在另一个部分。
【解决方案2】:

我强烈怀疑您需要进行一些回溯。你如何选择你的“好对子”?如果不选择允许最长替代链的“好对”序列会发生什么?

您可以将初始数组视为“状态”:

// using JSON notation; in C use structs, in Java use classes...
initialState = {
   numbers: [67108864 8 2 131072 268435456 256 16384 128 8 128],
   pairs: [[9, 4], [5,10], [6,9], [9, 10]], // several missing
   depth: 0
}

然后您可以尝试执行pairs.length 替换之一以前进到“子”状态(您将所选数字除以一个公因子,并增加“深度”conuter);但是有可能执行这些替换中的一个会消除执行另一个不同替换的可能性:例如,我可以将 9 与 4、10 或 6 配对......这意味着它通常是可能的到达不是最深死胡同的“死胡同”。

使用http://en.wikipedia.org/wiki/Backtracking 找到正确答案。如果它运行得太慢,您可以尝试一些修剪:通过跟踪使用的唯一数字数组来避免多次访问同一状态。

【讨论】:

  • 好的对作为输入。这是来自codeforces网站的一个问题。我不明白为什么答案不是 28 而实际上是 31。codeforces.com/contest/499/problem/E
  • 因为您以非最佳顺序使用这些对。按照维基百科链接
  • 谢谢。我阅读了维基链接。你能解释一下这个案例的最佳顺序以及你是如何得到它的吗?您将如何对其应用回溯?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-19
  • 2018-09-10
相关资源
最近更新 更多