问题描述
我需要找到范围 (45 000 000,50 000 000 +1) 中的所有数字,这些数字只有五个奇数除法器。偶数分隔符的数量没有限制。这里我的代码太慢了
listN=[]
for i in range (45000000,50000000+1):
sqrtI=i**0.5
counter=0
sqrtI=int(sqrtI)
for j in range (1,sqrtI+1):
divj,modj=divmod(i,j)
if modj==0:
if j%2==1:
counter+=1
if divj%2==1:
counter+=1
if counter >5:
break
if counter==5:
listN.append(i)
if i%100000==0: #
print(i)
print(listN)
解决方法
取一个奇数 n
。如果这个奇数 n
有一个奇数除数 m
,那么 n/m
也是一个奇数。但这意味着奇数除数成对出现,m
和 n/m
。数字 n
可以有 5 个奇数除数的唯一方法是,如果某对实际上具有相同的数字,即 m = n/m
。但这意味着 n = m*m
,即 n
必须是奇数的平方。因此,您不需要检查范围内的所有奇数,只需检查是奇数平方的奇数即可。
现在考虑偶数 n
。让我们将这个数除以 2,直到我们得到一个奇数 m
(例如,从 n=40
我们得到 40 -> 20 -> 10 -> 5
,所以 m = 5
)。 m
的任何奇数除数也将是 n
的奇数除数,反之亦然。因此,n
和 m
具有相同数量的奇数除数。因此,正如我们在上面看到的,数字 m
必须是奇数的平方。这意味着,n
必须是奇数乘以 2 的某个幂的平方。这意味着您不需要检查范围内的每个偶数,只检查那些是奇数乘以 2 的幂的平方。
更新
以下是示例实现:
def method1(a,b):
result = []
for n in range(a,b + 1):
m = n
while (m > 1) and (m % 2 == 0):
m /= 2
root = int(m ** 0.5 + 0.5)
if root * root != m:
continue
count = 0
for i in range (3,root):
if (i % 2 == 0) or (m % i != 0):
continue
count += 1
if count > 1:
break
if count == 1:
result.append(n)
return result
def generate_primes(start,end):
result = []
for n in range(start,end + 1):
if n % 2 == 0:
continue
root = int(n ** 0.5 + 0.5)
for i in range(3,root + 1):
if n % i == 0:
break
else:
result.append(n)
return result
def method2(a,b):
result = []
primes = generate_primes(3,int(b ** 0.25 + 0.5))
for p in primes:
n = p**4
while n < a:
n *= 2
while n <= b:
result.append(n)
n *= 2
return sorted(result)
a = 45000000
b = 50000000
print(method1(a,b))
print(method2(a,b))
第一个 method1
使用上述方法。第二个 method2
使用更高级的方法,速度大约快 100 倍。第二种方法的想法是生成 3 到区间上限的四次根之间的所有素数(在我们的例子中是 50000000,所以素数不能大于 84)。然后我们对所有这些质数进行 4 次方,并尝试将它们乘以 2,直到我们进入所需的区间。两种方法产生相同的输出
[45212176,45265984,47458321,48469444]
以下是方法 2 有效的详细证明:
要了解方法 2 的工作原理,我们需要继续分析方法 1。我们知道,为了有 5 个除数,我们的数 n
必须等于奇数乘以幂的平方两个:
n = m*m * (some power of 2)
其中 m
是某个奇数。数字 m*m
必须正好有 5 个奇数除数。但是,我们已经知道其中的 3 个:1、m
和 m*m
。因此,m*m
的奇数除数应该只存在 2 个,其中只有一个在 1 和 m
之间。
让我们将第一个奇数除数表示为 p
(它应该在 1 和 m
之间)。那么第二个奇数除数是 m*m/p
。数 p
必须是质数。如果不是,则 p
的任何约数也是 m*m
的约数。我们知道第二个除数是 m*m/p
,所以 m*m
必须能被 p
整除。但是因为 p
是质数 m
也应该被 p
整除:m = p*x
,其中 x 是某个(奇数)数。但是如果 x
不等于 p
,那么我们在 1 和 x
之间找到了另一个数 m
,它是 m*m
的除数。这是不可能的,因此 x
必须等于 p
和 m = p*p
。因此,我们已经证明,m*m = p^4
,即我们的数 n
必须是素数乘以 2 的某个幂的四次方。