不与V互质的最大数

Maximum number not coprime to V

本文关键字:最大数 不与      更新时间:2023-10-16

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

现在,我得到了多达100000个形式为{V,L,R}的查询,其中在每个查询中,我需要找到最大的数A[I],其中I在与给定值V不互质的范围[L,R]中。(也就是说,GCD(V,A[I](不等于1。(

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

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

示例:

  • 设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。

由于您有一个大数组,但只有一个V,因此从分解V开始应该会更快。在那之后,你的互质测试变成了简单地求取V的每个唯一因子的余数。

Daniel Bernstein的《在本质上线性的时间内分解成协时》(Journal of Algorithms 54:1,1-30(2005((回答了一个类似的问题,并被Nadia Heninger的《新研究:无需恐慌可分解密钥——只需注意你的Ps和Qs》用于识别坏的(重复因子(RSA模。这里的问题是在一组非常大的数字之间找到共同的因子,而不是一次一对。

假设

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,那么这将是非常有效的。

EDIT我没有注意到数组不必包含所有整数。在这种情况下,对其进行筛选,即给定素数p_1。。。,p_n创建一个"反向"筛(即范围[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与不在multiples中的[L, R]范围内的每个数是互素的。现在您只需执行:

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,2]范围内(。由于我们处理的是集合(std::set?(,因此不会有重复(12和18(:

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

现在浏览initial_array并检查multiples中的值。我们得到最大的这样的数字是CCD_ 19。事实上,CCD_ 20与CCD_。

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

给定一个数n包含O(logn(素数,该列表将使用O(nlogN(内存。

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