我正在尝试解决following problem,我将其缩减为: 找到(N!)^ 2
的除数我编写了我的解决方案,我在此处作为答案(因为没有被指责不做任何工作),并且即使是大数字也能正常快速地工作,但因为它没有通过所有的由于超时测试,我认为我的算法效率不高。
以下是我的想法概述:
a0^b1*a1^b1*...*an^bn
,其中(1 + b1)*(1 + b2)*...*(1 + bn)
除数M^2
会有(1 + 2b1)*(1 + 2b2)*...*(1 + 2bn)
除数我认为这个解决方案非常有效,但看起来有更好的方法。 谁能建议我一个更好的方法呢?
答案 0 :(得分:7)
您的问题有一个简单有效的解决方案。请注意n!
是:
1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * ... * n
让我们考虑一下素数因子在此产品中出现的次数,例如2
。
每2
个因素出现一次。但是,每4
个因素出现两次。并且每8
个因素出现三次等。
换句话说,因子2
将出现在n!
sum(n//(2**e) for e in range(1, n))
次。对于任何素因子k
也是如此。
您可以使用以下方法实现此计算:
import itertools as it
def exp_for_factor_in_factorial(factor, n):
total = 0
for e in it.count(1):
if factor ** e > n:
break
total += n // factor**e
return total
现在,为了找到n!
的所有素数因子,我们需要找到最多n
的所有素数,这可以通过eratosthenes轻松完成:
import math
def sieve(n):
nums = [True] * (n+1)
nums[:2] = [False]*2
nums[4::2] = [False] * math.ceil((n-3)/2)
for i in range(3, int((n+1)**.5)+1, 2):
if nums[i]:
for j in range(i*i, n+1, 2*i):
nums[j] = False
return [i for i,k in enumerate(nums) if k]
这使我们可以获得n!
的分解:
def get_factorization_factorial(n):
primes = sieve(n)
factors = []
for p in primes:
factors.append((p, exp_for_factor_in_factorial(p, n)))
return factors
最后,要计算分解中的除数数,可以使用已经提到的公式:
import operator as op
from functools import reduce
def get_num_divisors(factorization):
return reduce(op.mul, (e+1 for _, e in factorization), 1)
所以最终答案可以获得:
def divs_of_squared_fact(n):
return get_num_divisors((p, 2*e) for p, e in get_factorization_factorial(n))
请注意,此解决方案的性能远高于您的解决方案:
In [41]: %%timeit
...: for i in range(2, 1000):
...: x = divs_of_squared_fact(i)
...:
1 loops, best of 3: 276 ms per loop
In [42]: %%timeit
...: for i in range(2, 1000):
...: x = divisorsOfFactorialSquare(i)
...:
1 loops, best of 3: 7.89 s per loop
能够产生大约(5000!)^2
中2ms
的除数的数量,而另一个则需要几乎半秒:
In [47]: %timeit divs_of_squared_fact(5000)
100 loops, best of 3: 2.07 ms per loop
In [48]: %timeit divisorsOfFactorialSquare(5000)
1 loops, best of 3: 439 ms per loop
嗯,实际上答案具有不同的渐近复杂度,因此在增加论证时,差异会变为无穷大。