威尔逊定理
内容
Wilson 定理
对于素数
对于整数
Wilson 定理指出
应用
阶乘与素数
在某些情况下,有必要考虑以某个素数
只有当阶乘同时出现在分数的分子和分母中时,这个问题才有意义。否则,后续项
因此,要计算
用
这种修正的阶乘,可用于快速计算各种带取模和组合数的公式的值。
计算余数的算法
计算上述去掉因子
可以清楚地看到,除了最后一个块外,阶乘被划分为几个长度相同的块。
块的主要部分
总共有
最后一个部分块的值可以在
这只留下每个块的最后一个元素。如果隐藏已处理的元素,可以看到以下模式:
这也是一个修正的阶乘,只是维数小得多。它是:
因此,在计算修改的阶乘
如果预先计算阶乘
计算余数算法的实现
具体实现不需要递归,因为这是尾部递归的情况,因此可以使用迭代轻松实现。在下面的实现中预计算了阶乘
因此时间复杂度为
实现
如果空间有限,无法存储所有阶乘,也可以只存储需要的阶乘,对它们进行排序,然后计算阶乘
Legendre 公式
如果想计算二项式系数模
Legendre 公式
其中
特别地,阶乘中 2 的幂次是
证明
将
第二个等号与等比数列求和公式很相似。由于涉及各位数字和,利用数学归纳法可以轻松证明。
实现
int multiplicity_factorial(int n, int p) {
int count = 0;
do {
n /= p;
count += n;
} while (n);
return count;
}
时间复杂度
以下记
Kummer 定理
组合数对一个数取模的结果,往往构成分形结构,例如谢尔宾斯基三角形就可以通过组合数模 2 得到。
如果仔细分析,
Kummer 定理
即
特别地,组合数中
Wilson 定理的推广
Wilson 定理的推广
对于素数
证明
依然考虑配对一个数与其逆元,也就是考虑关于
至此我们对 Wilson 定理的推广中的
下文两个推论中的
推论 1
对于素数
证明
令
将
至此得到了:
推论 2
对于素数
其中
记
右边的分母中括号内的项均在模
例题
解题思路
若
设
则
若
设
因此
参考代码
#include <iostream>
constexpr int M = 1e6 + 5, N = 3 * M + 7;
bool not_prime[N];
int sum[M];
int main() {
for (int i = 2; i < N; ++i)
if (!not_prime[i])
for (int j = 2; j * i < N; ++j) not_prime[j * i] = true;
for (int i = 1; i < M; ++i) sum[i] = sum[i - 1] + !not_prime[3 * i + 7];
int t;
std::cin >> t;
while (t--) {
int n;
std::cin >> n;
std::cout << sum[n] << std::endl;
}
}
本页面主要译自博文 Вычисление факториала по модулю 与其英文翻译版 Factorial modulo p。其中俄文版版权协议为 Public Domain + Leave a Link;英文版版权协议为 CC-BY-SA 4.0。
参考资料
- 冯克勤。初等数论及其应用。
创建日期: 2021年9月9日