【问题标题】:Modulo of factorial divided by factorial阶乘的模除以阶乘
【发布时间】:2022-01-17 02:51:57
【问题描述】:

如何计算a!/(b1! b2! ... bm!) modulo p,其中p 是质数? ab 的阶乘可能很大(long long int 不够),所以我需要传递模数。

【问题讨论】:

  • 有条件使其成为整数。显然,a>= max(b1,b2,...bm)。您是否有更多详细信息 - 例如如果 b1+b2...bm=a 那么您确定它是一个整数,因为它是混合 m 个大小为 bi 的组而不在组内排列的方式数。
  • @user3386109 因为 p 素数,您可以通过计算模逆来执行除法。我会将其扩展为答案。
  • Removing common factors leaves a multiplication。然后可以通过注意(a * b) mod p = ((a mod p) * (b mod p)) mod p来执行乘法。
  • 要去除公因子,您还可以获得a!b1!b2! 等的素数分解,然后将a! 的素数的指数减去每个b_i! 的素数。
  • 我会采用之前的建议来存储素因子。您有大约 19 个低于 60 的素因数。您将有一个 2D 数组存储 1..60 的那些,您可以使用正确的值对其进行初始化(通过外部计算并粘贴到代码中或使用 constexpr 函数,它确实计算正常,但在编译时执行)。第二个一维数组存储素数。一旦你知道分数结果的主要因素,它就是一个简单的循环乘法,并且不时做模(%)。

标签: c++ algorithm modulo factorial number-theory


【解决方案1】:

如果abs 和p 相当小,则更喜欢@KellyBundy 的取消因子或计算素因子的方法。

乘法和模运算

给定整数 mn 以及其他整数 k

(m * n) modulo k = ((m modulo k) * (n mod k)) modulo k

这允许计算较大的乘积 modulo p 而无需担心溢出,因为我们始终可以将参数保持在 [0, k) 范围内。

例如计算阶乘a! modulo k,在python中:

def fact(a, k):
    if a == 0:
        return 1
    else:
        return ((a % k) * fact(a - 1, k)) % k

除法和模运算

如果p 是一个素数,那么对于任何不能被p 整除的整数n,我们可以找到一个我称之为inv(n) 的整数,这样:

(n * inv(n)) modulo p = 1

这个号码被称为modular inversen。有多种算法可以找到模逆,我不会在这里描述(但请参见例如here)。

现在,给定整数 nm,并且假设 m / n 是整数,我们可以应用以下规则:

(m / n) modulo p = (m * inv(n)) modulo p

所以只要我们可以计算模逆,我们就可以将除法转换为乘法,然后应用前面的规则。

【讨论】:

  • 这个答案听起来像是取消因子是可选的,但通常您必须首先取消至少 p 的因子。答案的其他部分暗示了原因。假设 (m/n) 是一个整数;那么 (pm)/(pn) 也是如此。但是如果你不取消 p 那么分母是不可逆的,分子是零。
  • 是的,这很好。
  • 既然 OP 说模数是素数,inv(x) 可以通过费马小定理(使用 Python 的 pow 函数)为 pow(x, p-2, p)
  • 第三个参数是模数
【解决方案2】:

另一种方法,列出因子1a,然后用所有除数取消,然后以模p 相乘:

#include <iostream>
#include <vector>

int gcd(int a, int b) {
  return b ? gcd(b, a % b) : a;
}

int main() {
  int a = 60;
  std::vector<int> bs = {13, 7, 19};
  int p = 10007;

  std::vector<int> factors(a);
  for (int i=0; i<a; i++)
    factors[i] = i + 1;
  for (int b : bs) {
    while (b > 1) {
      int d = b--;
      for (int& f : factors) {
        int g = gcd(f, d);
        f /= g;
        d /= g;
      }
    }
  }
  int result = 1;
  for (int f : factors)
    result = result * f % p;
  std::cout << result;
}

打印 5744,与此 Python 代码相同:

from math import factorial, prod

a = 60
bs = [13, 7, 19]
p = 10007

num = factorial(a)
den = prod(map(factorial, bs))
print(num // den % p)

【讨论】:

    猜你喜欢
    • 2014-03-24
    • 1970-01-01
    • 2015-04-19
    • 1970-01-01
    • 2018-08-17
    • 1970-01-01
    • 1970-01-01
    • 2013-10-25
    • 1970-01-01
    相关资源
    最近更新 更多