【笔记】数论基础
-
乘法逆元
若 \(a\times b \equiv 1 (\bmod \ c)\),且 \(\gcd(a,b) = 1\),那么我们定义 \(a\) 为 \(b\) 的逆元,也可以称 \(a\) 是 \(b\) 在 \(\bmod \ c\) 意义下的倒数。
-
费马小定理
对于质数 \(p\) 和任意整数 \(a\),有 \(a^p \equiv a (\bmod \ p)\)。反之,若 \(a^p \equiv a (\bmod \ p)\),则 \(p\) 很有可能是质数。
对于上面的式子 \(a^p \equiv a (\bmod \ p)\),可以两边同时约去一个 \(a\),则有 \(a^{p-1} \equiv 1 (\bmod \ p)\)。
也就是说,如果我们要判断 \(p\) 是否为质数,我们可以随机选取一个整数 \(a\),然后计算 \(a^{p-1} (\bmod \ p)\),如果结果不为 \(1\),那么 \(p\) 一定不是质数。
-
二次探测定理 / \(\mathcal{Fermat}\) 测试
如果 \(p\) 是奇质数,则有 \(a^2 \equiv 1 (\bmod \ p)\) 的解为 \(a \equiv 1\) 或 \(a \equiv p - 1 (\bmod \ p)\)
证明如下:
-
\(\mathcal{Miller-Rabin}\) 质数测试
判断一个正整数 \(p\) 是否为质数 \((p \le10^{18})\)。
对于暴力做法:
bool isPrime(int a) {
if (a < 2) return 0;
for (int i = 2; i < a; ++i)
if (a % i == 0) return 0;
return 1;
}
显然超时。
需要用到 \(\mathcal{Miller-Rabin}\) 质数测试。
将费马小定理与二次探测定理结合,即为 \(\mathcal{Miller-Rabin}\) 质数测试。
单次测试失败概率为 \(\frac{1}{4}\),若进行了 \(k\) 轮测试,那么失败的概率为 \((\frac{1}{4})^k\)。

在进行 \(5\) 轮测试的情况下,失败的概率为 \(\frac{1}{0.0009765625}\),这几乎不可能发生。
当然这里的 \(k\) 最好在 \([8,20]\) 之间。
关于单轮的时间复杂度为 \(\mathcal{O(\log n)}\),总时间复杂度为 \(\mathcal{O(k\log n)}\)。
注意:需要使用 __int128,用 long long 会爆掉。
#include <iostream>
#define int long long
using namespace std;
int p, k;
int qmul(int a, int b, int mod) {
int c = (long double)a / mod * b;
int res = (unsigned int)a * b - (unsigned int)c * mod;
return (res + mod) % mod;
}
int quickpow(int a, int n, int mod) {
int res = 1;
while (n) {
if (n & 1) res = qmul(res, a, mod);
a = qmul(a, a, mod);
n >>= 1;
}
return res;
}
bool MR(int n) {
if (n < 3) {
return n == 2;
}
for (int i = 1; i <= k; i ++) {
int a = rand() % (n - 2) + 2;
if (quickpow(a, n - 1, n) != 1) {
return 0;
}
}
return 1;
}
signed main() {
cin >> p >> k;
cout << MR(p);
return 0;
}

浙公网安备 33010602011771号