FF 的除数(计算给定数的除数乘积的除数)
Posted
技术标签:
【中文标题】FF 的除数(计算给定数的除数乘积的除数)【英文标题】:FF's divisors (calculate number of divisors of product of divisors of given number) 【发布时间】:2018-01-13 16:22:41 【问题描述】:这是一些在线比赛的问题,但现在已经结束了,所以我想知道如何实际解决它。
给定数字 n,它有一些(对于数字 4,你有 1,2,4)除数(包括 1 和它本身)。如果 p 等于给定数 n 的所有除数的乘积,求 p 的除数个数。
我试图解决它,但我的解决方案只是优化了蛮力,所以我正在寻找具有数学背景的快速解决方案。
【问题讨论】:
n 和 p 的约束是什么?它很容易在 O(sqrt(n) + sqrt(p)) 中解决。 1 coj.uci.cu/24h/problem.xhtml?pid=2849&lang=en987654321@发现同样的问题 见Is it okay to just ask for an algorithm to a problem?。另外,这是一个计算机科学问题而不是编程问题,所以你最好在Computer Science Stack Exchange问。 @АндрейМоскаленко 不需要sqrt(p)
,请看我的回答。
【参考方案1】:
我们来看一个例子:105
105
有 8 个除数:
1, 3, 5, 7, 15, 21, 35, 105
除数乘积的除数是105^(d(105) / 2)
。通过配对每个除数,我们可以很容易地看到这一点:
1, 3, 5, 7, 15, 21, 35, 105
a b c d d c b a
=> a*a * b*b * c*c * d*d
意思是我们得到105
乘以自身d(105) / 2
次。
现在我们来看看105
的质因数:
3, 5 and 7
除数的乘积中每个都有d(105) / 2 = 4
:
3*3*3*3 * 5*5*5*5 * 7*7*7*7
上面的被乘数有几种组合方式?
5 ways to set 3
5 ways to set 5
5 ways to set 7
5 * 5 * 5 = 125
105
的除数的乘积有125
除数。
一般公式:
f(n):
d = product(map (\x -> x + 1) prime_counts)
m = d / 2
counts = map (\x -> m * x + 1) prime_counts
return product(counts)
随机示例:
f(63):
d = product([3, 2]) = 6
m = 6 / 2 = 3
counts = map (\x -> m * x + 1) [2, 1] = [7, 4]
return product([7,4]) = 28
63
、1 * 3 * 7 * 9 * 21 * 63 = 250047
的除数的乘积有28
除数。
【讨论】:
【参考方案2】:我认为这项任务基于以下事实:
如果某个数字A
被分解为P1^N1*P2^N2*...*Pk^Nk
,那么A
的除数总数为(N1+1)*(N2+1)*...*(Nk+1)
。很容易看出为什么会这样:每个素数除数 Pi
可以是从 0
到 Ni
的任何幂。
如果D
是A
的除数,那么A/D
也是A
的除数
因此,您从分解 n
开始并计算其除数的总数 - 我们称之为 T
。检查n
是否是一个完美的正方形也很重要(即它的所有Ni
是否都是偶数)。
现在,当您有 n
的因式分解时,您需要得到 p
的因式分解。显然,所有的主要因素都是相同的,只有权力会不同。您可以根据事实 #1 和 #2 计算幂。如果将n
的所有除数组合成对D
+ n/D
,您会注意到相乘后的每一对都恰好产生n
。唯一的例外可能是 n
是一个完美的正方形,然后 sqrt(n)
= n/sqrt(n)
所以没有对。无论如何,您可能会看到p
正是n^(T/2)
。 (注意:只有当n
中的所有Ni
都是偶数时,T
才是奇数,即如果n
是一个完美的正方形。)
所以这意味着要获得p
的分解幂,您应该将n
的所有分解幂乘以T/2
,然后使用来自事实的公式计算p
的除数总数#再 1 次。
我希望这个算法中最长的部分应该是n
的因式分解,这是一个经过充分研究的问题。其余的应该很快。
【讨论】:
【参考方案3】:这是一种算法。这可能是可以改进的,但这需要更多的时间和思考。
假设n = p^e * N
,其中p
是质数,e
(代表“指数”)是一个正整数,并且N
不能被p
整除。 (即p^e
在n
的规范素数分解中。)那么如果我们说N
有c
因子(c代表“计数”),即f1, f2, ..., fc
,其乘积是P
,那么n
的因子是
1 * f1, 1 * f2, ... 1 * fc
p * f1, p * f2, ... p * fc
...
p^e * f1, p^e * f2, ... p^e * fc
那么第一行的乘积就是1^c * f1 * f2 * ... * fj
,也就是P
。第二行有产品p^c * f1 * f2 * ... * fj
,即p*c * P
。最后一行的产品(p^(e))^c * f1 * f2 * ... * fj
就是p^(e*c) * P
。如果我们让T(e)
成为e
th 三角数,即1 + 2 + ... + e
,那么n
所有这些因素的乘积是
p^(c * T(e)) * P^(e+1)
计算T(e)
的快捷方式是e * (e+1) / 2
。计算c
的捷径是使用N
的所有质因数及其指数e1, ..., ek
在N
的质因数分解中使用c = (e1 + 1) * ... * (ek + 1)
。这两条捷径在数论中是众所周知的。
所以这是一个伪代码算法。
# Find the prime factorization of the product of the factors of n
c = 1
set factor-list and exponent-list to empty lists
for each prime factor p of n:
# Update the prime factorization of the product of factors
e = the exponent of p in the prime factorization of n
multiply each exponent in the exponent-list by e + 1
append p to the factor list
T = e * (e+1) / 2 # the e'th triangular number
append c * T to the exponent-list
# Update the number of divisors of the current product of factors
c = c * (e+1)
# Find the number of divisors of the final product
result = 1
for each x in the exponent-list:
result = result * (x + 1)
return result
我在 Python 3.6 中编写了一个函数来测试算法,它检查到 n = 10000
。 (这个值很低,因为检查函数比我正在检查的函数慢得多。)算法略有改变,找到n
的下一个主要除数的代码更简单但比必要的慢。
def cnt_divisors_of_prod_of_divisors(n):
"""Return the count of the divisors of the product of the divisors
of n
"""
# Find the prime factorization of the product of the divisors of n
num = n # number to find prime factorization
cnt = 1 # number of divisors of prime-factorization of n already done
divisors = [] # prime divisors of product of divisors of n
exponents = [] # their exponents in the product of divisors of n
p = 1 # a fake prime divisor of n
while num > 1:
# Find the next prime divisor of n
p += 1
while num % p:
p += 1
# Find the exponent of that prime divisor
e = 1
num = num // p
while num % p == 0:
e += 1
num = num // p
# Multiply each exponent in the exponent-list by e + 1
for j in range(len(exponents)):
exponents[j] *= e + 1
# Append p to the divisor list
divisors.append(p)
# Append the new exponent of p in the product to the exponent-list
T = e * (e+1) // 2 # e'th triangular number
exponents.append(cnt * T)
# Update the number of divisors of n
cnt *= e + 1
# Find the number of divisors of the final product
result = 1
for x in exponents:
result *= x + 1
return result
我机器上的代码 n = 10**7
需要 6.03 微秒,尽管这个时间很大程度上取决于 n
的值。这似乎可以接受!
【讨论】:
以上是关于FF 的除数(计算给定数的除数乘积的除数)的主要内容,如果未能解决你的问题,请参考以下文章