Pollard-Rho 素性测试
概念讲解
Miller-Rabin 素性测试
用于判断一个大数是否是素数。
Pollard-Rho 算法
用于分解大整数的因数。
实现
Miller-Rabin 素性测试
12345678910111213141516171819202122232425262728293031323334353637383940414243long long quickPowerMod(long long a, long long n, long long mod) {
long long result = 1;
a %= mod;
while (n > 0) {
if (n % 2 == 1) result = result * a % mod;
a = a * a % mod;
n /= 2;
}
return result;
}
bool millerRabin(long long n) {
if (n < 2) return false;
if (n == 2 || n == 3) return true;
if (n % 2 == 0) return false;
long long d = n - 1;
int r = 0;
while (d % 2 == 0) {
d /= 2;
r++;
}
for (int a : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}) {
if (a >= n) continue;
long long x = quickPowerMod(a, d, n);
if (x == 1 || x == n - 1) continue;
bool found = false;
for (int i = 0; i < r - 1; i++) {
x = x * x % n;
if (x == n - 1) {
found = true;
break;
}
}
if (!found) return false;
}
return true;
}Pollard-Rho 算法
12345678910111213141516171819202122232425262728293031long long pollardRho(long long n) {
if (n % 2 == 0) return 2;
long long x = rand() % (n - 2) + 2;
long long y = x;
long long c = rand() % (n - 1) + 1;
long long d = 1;
while (d == 1) {
x = (x * x % n + c) % n;
y = (y * y % n + c) % n;
y = (y * y % n + c) % n;
d = __gcd(abs(x - y), n);
if (d == n) return pollardRho(n);
}
return d;
}
void factorize(long long n, vector<long long>& factors) {
if (n == 1) return;
if (millerRabin(n)) {
factors.push_back(n);
return;
}
long long d = pollardRho(n);
factorize(d, factors);
factorize(n / d, factors);
}考点分析
初赛考查方式
- 选择题: 素性测试的概念
- 程序阅读: 理解 Miller-Rabin
- 编程题: 大数分解
常见题型
- 大数素性判断
- 大数因数分解
例题精讲
例题 1:大数素性判断
题目: 判断一个大数是否是素数。
解答:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960#include <iostream>
#include <cstdlib>
using namespace std;
long long quickPowerMod(long long a, long long n, long long mod) {
long long result = 1;
a %= mod;
while (n > 0) {
if (n % 2 == 1) result = result * a % mod;
a = a * a % mod;
n /= 2;
}
return result;
}
bool millerRabin(long long n) {
if (n < 2) return false;
if (n == 2 || n == 3) return true;
if (n % 2 == 0) return false;
long long d = n - 1;
int r = 0;
while (d % 2 == 0) {
d /= 2;
r++;
}
for (int a : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}) {
if (a >= n) continue;
long long x = quickPowerMod(a, d, n);
if (x == 1 || x == n - 1) continue;
bool found = false;
for (int i = 0; i < r - 1; i++) {
x = x * x % n;
if (x == n - 1) {
found = true;
break;
}
}
if (!found) return false;
}
return true;
}
int main() {
long long n;
cin >> n;
if (millerRabin(n)) {
cout << n << " 是素数" << endl;
} else {
cout << n << " 不是素数" << endl;
}
return 0;
}练习题
- 洛谷 P3383 Miller-Rabin 素性测试
查看答案
思路:使用 Miller-Rabin 素性测试判断大数是否为素数。
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859#include <iostream>
using namespace std;
long long quickPowerMod(long long a, long long n, long long mod) {
long long result = 1;
a %= mod;
while (n > 0) {
if (n % 2 == 1) result = result * a % mod;
a = a * a % mod;
n /= 2;
}
return result;
}
bool millerRabin(long long n) {
if (n < 2) return false;
if (n == 2 || n == 3) return true;
if (n % 2 == 0) return false;
long long d = n - 1;
int r = 0;
while (d % 2 == 0) {
d /= 2;
r++;
}
for (int a : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}) {
if (a >= n) continue;
long long x = quickPowerMod(a, d, n);
if (x == 1 || x == n - 1) continue;
bool found = false;
for (int i = 0; i < r - 1; i++) {
x = x * x % n;
if (x == n - 1) {
found = true;
break;
}
}
if (!found) return false;
}
return true;
}
int main() {
int n, m;
cin >> n >> m;
while (m--) {
long long x;
cin >> x;
cout << (millerRabin(x) ? "Yes" : "No") << endl;
}
return 0;
}- 洛谷 P4718 Pollard-Rho
查看答案
思路:使用 Pollard-Rho 算法分解大整数。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103#include <iostream>
#include <cstdlib>
#include <vector>
#include <algorithm>
using namespace std;
long long quickPowerMod(long long a, long long n, long long mod) {
long long result = 1;
a %= mod;
while (n > 0) {
if (n % 2 == 1) result = (__int128)result * a % mod;
a = (__int128)a * a % mod;
n /= 2;
}
return result;
}
bool millerRabin(long long n) {
if (n < 2) return false;
if (n == 2 || n == 3) return true;
if (n % 2 == 0) return false;
long long d = n - 1;
int r = 0;
while (d % 2 == 0) {
d /= 2;
r++;
}
for (int a : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}) {
if (a >= n) continue;
long long x = quickPowerMod(a, d, n);
if (x == 1 || x == n - 1) continue;
bool found = false;
for (int i = 0; i < r - 1; i++) {
x = (__int128)x * x % n;
if (x == n - 1) {
found = true;
break;
}
}
if (!found) return false;
}
return true;
}
long long pollardRho(long long n) {
if (n % 2 == 0) return 2;
long long x = rand() % (n - 2) + 2;
long long y = x;
long long c = rand() % (n - 1) + 1;
long long d = 1;
while (d == 1) {
x = ((__int128)x * x % n + c) % n;
y = ((__int128)y * y % n + c) % n;
y = ((__int128)y * y % n + c) % n;
d = __gcd(abs(x - y), n);
if (d == n) return pollardRho(n);
}
return d;
}
long long maxFactor = 0;
void factorize(long long n) {
if (n == 1) return;
if (millerRabin(n)) {
maxFactor = max(maxFactor, n);
return;
}
long long d = pollardRho(n);
factorize(d);
factorize(n / d);
}
int main() {
int n;
cin >> n;
while (n--) {
long long x;
cin >> x;
if (millerRabin(x)) {
cout << "Prime" << endl;
} else {
maxFactor = 0;
factorize(x);
cout << maxFactor << endl;
}
}
return 0;
}- 洛谷 P1075 质因数分解
查看答案
思路:试除法分解质因数。
12345678910111213141516#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) {
cout << n / i << endl;
break;
}
}
return 0;
}易错点
⚠️ 注意:
- Miller-Rabin 要选择合适的测试基数
- Pollard-Rho 要注意随机化
- 大数分解要注意溢出
- Pollard-Rho 是数论的高级内容