质数筛学习笔记
ShiRoZeTsu · · 算法·理论
判断质数
原理:根据质数定义,若
bool ok = true;
for(int i = 2; i < p; i++)
if(p%i == 0) { ok = false; break; }
//ok = true 表示是质数, ok = false 表示是合数
时间复杂度
优化
对于任意正整数
当
我们令其中
什么时候两边取等呢?显然当
于是我们判断
代码:
bool ok = true;
for(int i = 2; i*i <= p; i++)
if(p%i == 0) { ok = false; break; }
//为了不使用 sqrt,这里将式子两边同时平方
时间复杂度
分解质因数
这个过程类似于判断质数,不过实现方式只需要从小到大一一判断,然后将对应的质因子除去即可.
先给出代码:
for(int i = 2; i <= p; i++) {
if(p%i == 0) {
px[++tot] = i;
while(p%i == 0) {
cnt[tot]++;
p /= i;
}
}
//px 表示分解出来的质因数数组
//tot 表示当前分解出来的质因数个数
//cnt 表示每个质因数在 p 里面出现的个数
}
可能你有所疑惑,为什么这里只需要判断
对于一个大于
而代码中求质因数的顺序,也是从小到大枚举因数,这样就保证 “当
因此这份代码不仅求出了 px 数组中,你还会发现这些质因数一定是从小到大排序的.
此外……
还有一个东西叫 Pollard rho 算法,它能在
质数筛
埃氏筛
根据 “质数除本身以外的倍数都是合数”,当我们从
代码:
for(int i = 2; i <= n; i++) {
if(!vis[i]) {
prime[++tot] = i;
for(int j = 2; j*i <= n; j++)
vis[i*j] = true;
}
//prime 是用来存储筛出的质数的数组
//tot 表示当前筛出的质数总数
//vis 用来表示某个数字是否被打上标记(合数)
}
时间复杂度
线性筛
在埃氏筛中,每个数字可能被其质因数筛多次,而如果每个数字最多只被筛一次就好了. 于是线性筛算法为我们提供了这样一个模板:
for(int i = 2; i <= n; i++) {
if(!vis[i]) prime[++tot] = i;
for(int j = 1; j <= tot && i*prime[j] <= n; j++) {
vis[i*prime[j]] = true;
if(i%prime[j] == 0) break;
}
}
时间复杂度
另外,你还需要知道的是:在线性筛算法中,每个合数只会被其最小值因子筛掉,这个性质常用来线性求出一些数论函数的值,有相当大的实用价值.
下节课我们将会学习欧拉函数相关的内容,其中求解欧拉函数的方法将会与线性筛高度结合,因此请你牢记线性筛的相关内容.