需要帮助在时间复杂度方面有效地解决以下问题

时间:2016-07-23 23:17:57

标签: algorithm performance complexity-theory

我正在努力解决过去两天的问题。除了暴力之外,我想不出任何解决方案。任何类型的提示或参考将不胜感激。 TIA。

“给定N个不同的素数整数,即p1p2,...,pN和间隔[L,R]。计算此区间中的整数个数可以被至少一个给定的素数整除。“

N 非常小(1 <= N <= 10)并且L,R非常大(1 <= L <= R <= 10 ^ 10)

2 个答案:

答案 0 :(得分:2)

首先注意,更容易限制问题,并忽略下限(即:处理L = 1)。如果我们可以计算可被任何N的素数&lt; = N整除的数字,我们也可以通过从计数&lt; = R中减去数字&lt; = L-1的数量来计算它们。

给定任何数字x,数字&lt; = R可被x整除的数是floor(R / x)。

现在,我们可以应用inclusion-exclusion principle来获得结果。首先,我将手动显示3个素数p1,p2和p3的结果,然后给出一般结果。

由p1,p2或p3整除的数字&lt; = R的数量为:

R / p1 + R / p2 + R / p3
- R / (p1p2) - R / (p1p3) - R / (p2p3)
+ R / (p1p2p3)

(这里假设/为四舍五入整数除法。)

一般情况如下:

sum((-1)^(|S|+1) * R / prod(S) for S a non-empty subset of {p1, p2, .., pN}).

此处S范围超过素数的所有子集,prod(S)是子集中素数的乘积,初始项在-1和+1之间变化,具体取决于子集的大小

对于你的问题,N&lt; = 10,所以有1023个非空子集,其中有少量东西需要迭代。

这是一些Python代码示例:

from itertools import *

def powerset(iterable):
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

def prod(ns):
    r = 1
    for n in ns:
        r *= n
    return r

def divs(primes, N):
    r = 0
    for S in powerset(primes):
        if not S: continue
        sign = 1 if len(S) % 2 else -1
        r += sign * (N // prod(S))
    return r

def divs_in_range(primes, L, R):
    return divs(primes, R) - divs(primes, L-1)

请注意,此代码的运行时间或多或少仅取决于质数的数量,而不取决于L和R的大小。

答案 1 :(得分:1)

假设n是区间大小,N是常数。

对于每个素数p,在由素数整除的区间中应该存在大致(R-L)/ p数。

找到第一个可被p区分的数字:L'= L +(p - L%p)。

现在,如果L'&gt; R,没有;否则有1 +楼((R-L')/ p)。

示例:3,[10,20]:

L'= 10 + 3 - 10%3 = 12.

在区间内可被3整除的数字:1 + floor((20 - 12)/ 3)= 3

注意:到目前为止,我们还没有使用p1..pN是素数的事实。

剩下的问题似乎是:如何避免计算多次可被多个素数整除的数字?示例:假设我们有3,5和[10,20],我们需要避免计算15次......

也许我们可以使用上面的计数算法计算(p1 * p2)等的可分性,并相应减少总数?如果N是常量,那么它应该仍然是常量时间。因为p1 ... pN是素数,所以它们的所有产品都需要不同(因为任何数字都不能超过一个主要的因子分解)。