Loading

质数和约数

试除法

思想:

要检验一个数字 \(n\) 是否为质数,将 \(n\) 除以 \(1\sim \sqrt n\),如果有一个数字刚好整除 \(n\),那么 \(n\) 为合数,否则 \(n\) 为奇数。

代码:

bool prime(int x) {
    if (x < 2) return false;
	for (int i = 2; i <= x / i; i++) {
		if (x % i == 0) {
			return false;
		}
	}
	return true;
}

埃氏筛

思想:

埃氏筛直接利用质数的定义。

我们易知一个数 \(x\)\(n\) 倍(\(n \ne 1\))一定是一个合数,

那么我们遇到一个质数时 \(x\),我们可以把它的倍数 \(xn(n\ne 1)\) 全部标记为不是质数

例:

遇到质数 \(2\)(绿色):

image

遇到质数 \(3\)(红色):

image

遇到质数 \(5\)(橙色):

image

遇到质数 \(7\)(蓝色):

image

等等。

我们还有一些优化:

  1. 我们遇到质数 \(x\),可以直接从 \(x^2\) 开始标记,因为前面的 \(x \cdot i\) 已经被更小的质数筛掉了,比如 \(20\) 通过 \(5 \times 4\) 筛掉,但早已经通过 \(2 \times 10\) 筛掉了。

  2. 我们可以只枚举 \(1 \sim \sqrt n\) 的质数就可以了,道理与试除法相同。

代码:

int n;
int prime[N], cnt;
bool is_not_prime[N];

void get_prime() {
    is_not_prime[0] = is_not_prime[1] = true;
    for (int i = 2; i <= n / i; i++) {
        if (!is_not_prime[i]) {
            for (int j = i * i; j <= n; j += i) {
                is_not_prime[j] = true;
            }
        }
    }
    for (int i = 2; i <= n; i++) {
        if (!is_not_prime[i]) {
            prime[++cnt] = i;
        }
    }
}

欧拉筛

思想:

欧拉筛也叫线性筛,

它也是通过一个质数乘以一个不为 \(1\) 的数去掉合数的。

只是它规定每一个数字都是被它最小的质因子筛除。

比如 \(6\) 有质因子 \(2, 3\),但是我们只会通过 \(2\) 去筛掉 \(6\),而不是 \(3\)

所以欧拉筛的思路就是:

  1. 遇到一个数字 \(x\),如果这个数字是质数,那么放入质数队列;
  2. 从小到大枚举质数队列中质数作为将要筛掉的数的最小质因数 \(p\),不断地用 \(p\) 乘以刚刚枚举的 \(x\) 得到数字 \(s\),将 \(s\) 标记为不是质数,直到不能保证 \(s\) 的最小质因数为 \(p\) 时停止;

现在我们想一想什么时候停止,也就是什么时候不能保证 \(s\) 的最小质因数为 \(p\)

实际上,如果刚好 \(x \mod p\) 等于 \(0\) 时可以停止(注意此时 \(p\) 是从前往后枚举)。

因为这样,\(p\) 一定是 \(x\) 的最小质因数,那么任何大于 \(p\) 的数 \(k\),乘以 \(x\) 得到的 \(x \times k = b\) 的最小质因数也应是 \(p\),所以不能往后枚举质数,因为不能保证最小质因数是 \(p\)

代码:

int prime[N], cnt;              // 记录质数的数组
bool is_not_prime[N];           // 标记某个数字不是质数的bool数组

void get_prime(int n) {
    is_not_prime[0] = is_not_prime[1] = true;
    for (int i = 2; i <= n; i++) {
        if (!is_not_prime[i]) prime[++cnt] = i;     // 记录质数
        for (int j = 1; j <= cnt && prime[j] * i <= n; j++) { // 枚举质数列表
            is_not_prime[prime[j] * i] = true;      // 标记不是质数
            if (i % prime[j] == 0) break;           // 何时停止?
        }
    }
}

posted @ 2023-07-14 11:45  SunnyYuan  阅读(20)  评论(0编辑  收藏  举报