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

631 * 3 * 7 * 9 * 21 * 63 = 250047 的除数的乘积有28 除数。

【讨论】:

【参考方案2】:

我认为这项任务基于以下事实:

    如果某个数字A 被分解为P1^N1*P2^N2*...*Pk^Nk,那么A 的除数总数为(N1+1)*(N2+1)*...*(Nk+1)。很容易看出为什么会这样:每个素数除数 Pi 可以是从 0Ni 的任何幂。

    如果DA 的除数,那么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^en的规范素数分解中。)那么如果我们说Nc因子(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) 成为eth 三角数,即1 + 2 + ... + e,那么n 所有这些因素的乘积是

p^(c * T(e)) * P^(e+1)

计算T(e) 的快捷方式是e * (e+1) / 2。计算c 的捷径是使用N 的所有质因数及其指数e1, ..., ekN 的质因数分解中使用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 的除数(计算给定数的除数乘积的除数)的主要内容,如果未能解决你的问题,请参考以下文章

Go标准包RPC的使用

javascript 计算给定数字的所有除数。

直到啥数字可以在 5 秒内找到给定数字的除数 [关闭]

CRC除数计算

计算整数的除数而不只是枚举它们(或估计如果不可能)? [关闭]

Oracle中计算除法——解决除数为零报错