【问题标题】:FF's divisors (calculate number of divisors of product of divisors of given number)FF 的除数(计算给定数的除数乘积的除数)
【发布时间】:2025-11-27 18:50:01
【问题描述】:

这是一些在线比赛的问题,但现在已经结束了,所以我想知道如何实际解决它。

给定数字 n,它有一些(对于数字 4,你有 1,2,4)除数(包括 1 和它本身)。如果 p 等于给定数 n 的所有除数的乘积,求 p 的除数个数。

我试图解决它,但我的解决方案只是优化了蛮力,所以我正在寻找具有数学背景的快速解决方案。

【问题讨论】:

标签: c++ algorithm math


【解决方案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】:

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

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

    2. 如果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 的值。这似乎可以接受!

      【讨论】: