质数的定义
若一个正整数除了
质数的分布
对于一个足够大的整数
质数的判定
试除法
cpp
bool is_prime(int n) {
if (n < 2) return false;
for (int i = 2; i <= n / i; i++) {
if (n % i == 0) return false;
}
return true;
}埃氏筛法
cpp
const int N = 1000000;
int primes[N], cnt = 0;
bool is_prime[N]; // is_prime[i] 为 true 表示 i 是质数
void get_primes(int n) {
memset(is_prime, true, sizeof is_prime);
is_prime[0] = is_prime[1] = false;
for (int i = 2; i <= n; i++) {
if (!is_prime[i]) continue;
primes[cnt++] = i;
for (int j = i * i; j <= n; j += i) {
is_prime[j] = false;
}
}
}线性筛法
埃氏筛法存在的问题是同一个合数可能会被重复标记,这是因为它没有确定唯一产生某一合数的方式!
线性筛法通过从大到小累计质因子的方式标记每个合数,举例来说,
设数组
- 依次考虑
之间的每一个数 。 - 若
,说明 是质数。 - 扫描不大于
的每一个质数 ,令 ,也就是再 的基础上累积一个质因子 ,因为 ,所以 就是合数 的最小质因子。
由此,每个合数
cpp
const int N = 1000000;
int v[N], primes[N], cnt = 0;
void get_primes(int n) {
for (int i = 2; i <= n; i++) {
if (v[i] == 0) {
// i 是质数
v[i] = i;
primes[++cnt] = i;
}
// 给当前数 i 累积质因子
for (int j = 1; j <= cnt; j++) {
// i 存在比 primes[j] 小的质因子,或者 i * primes[j] 大于 n
if (primes[j] > v[i] || i * primes[j] > n) break;
// primes[j] 是合数 i * primes[j] 的最小质因子
v[i * primes[j]] = primes[j];
}
}
}或者更一般的写法:
cpp
const int N = 1000000;
int primes[N], cnt = 0;
bool not_prime[N]; // not_prime[i] 为 true 表示 i 不是质数
void get_primes(int n) {
for (int i = 2; i <= n; i++) {
if (!not_prime[i]) primes[cnt++] = i;
for (int j = 0; j < cnt && primes[j] <= n / i; j++) {
not_prime[i * primes[j]] = true;
if (i % primes[j] == 0) break; // 魔法优化
}
}
}算术基本定理
对于任意正整数
分解质因数
cpp
void factorize(int n) {
for (int i = 2; i <= n / i; i++) {
if (n % i == 0) {
int cnt = 0;
while (n % i == 0) {
n /= i;
cnt++;
}
cout << i << ' ' << cnt << endl;
}
}
// n 中至多只包含一个大于 sqrt(n) 的质因子
if (n > 1) cout << n << ' ' << 1 << endl;
}