我正在努力解决过去两天的问题。除了暴力之外,我想不出任何解决方案。任何类型的提示或参考将不胜感激。 TIA。
“给定N个不同的素数整数,即p1
,p2
,...,pN
和间隔[L,R]
。计算此区间中的整数个数可以被至少一个给定的素数整除。“
N 非常小(1 <= N <= 10)并且L,R非常大(1 <= L <= R <= 10 ^ 10)
答案 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是素数,所以它们的所有产品都需要不同(因为任何数字都不能超过一个主要的因子分解)。