最大数量与V无关

时间:2014-03-12 14:42:29

标签: c++ algorithm

给定N个整数的固定数组A,其中N <= 100,000且阵列的所有元素也小于或等于100,000。 A中的数字不是单调增加或连续或以其他方便组织的。

现在我被给予100,000个{V,L,R}形式的查询,其中在每个查询中我需要找到最大数A [i],其中i在[L,R]范围内不是互质的具有给定值V.(即GCD(V,A [i])不等于1.)

如果不可能,那么也要告诉你给定范围内的所有数字都与V互质。

一种基本方法是从L和R之间的每个A [i]迭代并用值V计算GCD,从而找到最大值。但如果查询的数量也可以达到100,000,那么有没有更好的方法呢?在这种情况下,每次检查每个数字的效率太低。

示例:

  • 设N = 6,数组为[1,2,3,4,5,4],V为2,范围[L,R]为[2,5]。
  • 然后答案是4。

说明:

GCD(2,2)=2
GCD(2,3)=1
GCD(2,4)=2
GCD(2,5)=1

所以最大值是4。

4 个答案:

答案 0 :(得分:0)

由于您有一个大型数组但只有一个V,因此通过分解V开始应该更快。之后,你的互质测试变得简单地找到每个独特因子V的模数。

答案 1 :(得分:0)

让我们说

V = p_1*...*p_n

其中p_i是素数(您可以将其限制为不同的素数)。现在答案是

result = -1
for p_i:
    res = floor(R / p_i) * p_i
    if res >= L and res > result:
        result = res

因此,如果您能快速分解V,那么这将非常有效。

编辑我没有注意到数组不必包含所有整数。在那种情况下,筛选它,即给定素数p_1,...,p_n创建一个&#34;反转&#34;筛(即[L, R]范围内的所有素数倍数)。然后你可以只用你的初始数组做一个筛子的交叉点。

EDIT2 要生成所有倍数的集合,您可以使用此算法:

primes = [p_1, ..., p_n]
multiples = []
for p in primes:
    lower = floor(L / p)
    upper = floor(R / p)
    for i in [lower+1, upper]:
        multiples.append(i*p)

从数学上可以看出,V[L, R] multiples范围内的每个数字相互联系。现在你只需:

solution = -1
for no in initial_array:
    if no in multiples:
        solution = max(solution, no)

请注意,如果您将result设置为一组,则if no in result:检查为O(1)

示例让我们说V = 6 = 2*3initial_array = [7,11,12,17,21]以及L=10R=22。让我们从倍数开始。按照算法我们得到

multiples = [10, 12, 14, 16, 18, 20, 22, 12, 15, 18, 21]

前7是2的倍数(范围[10,22]),后4是3的倍数(范围[10,22])。由于我们处理集合(std::set?),因此不会有重复项(12和18):

multiples = [10, 12, 14, 16, 18, 20, 22, 15, 21]

现在浏览initial_array并查看multiples中的值。我们得到的最大数字是21。确实216不相同。

答案 2 :(得分:0)

Daniel Bernstein的"Factoring into coprimes in essentially linear time"(Journal of Algorithms 54:1,1-30(2005))回答了一个类似的问题,用于识别Nadia Heninger "New research: There's No Need to Panic Over Factorable Keys--Just Mind Your Ps and Qs"`的不良(重复因子)RSA模型。问题在于找到一大堆非常大的数字之间的共同因素,而不是一次一对。

答案 3 :(得分:0)

对每个A元素进行因子分析,并为每个可能的素数因子存储包含该因子的数字的排序列表。

如果数字n包含O(log n)素因子,则此列表将使用O(N log N)内存。

然后,对于每个查询(V,L,R),在V中搜索每个素数因子,在[L,R]中包含该因子的最大数量是多少(这可以通过简单的二进制搜索来完成)