文章目录
素数的定义
啊,耳熟能详。素数又称质数,一个大于 1 1 1的自然数,除了 1 1 1和它本身外,不能被其他自然数整除,换句话说就是该数除了 1 1 1和它本身以外不再有其他的因数;否则称为合数。啊! 1 1 1不是素数啊
素数的判断
啊,也耳熟能详了,暴力枚举一下除 1 1 1和本身的自然数是否会被整除。
bool is_prime(int x) {
for(int i=2;i<x;i++)
if(x%i==0) return 0;
return 1;
}
啊,其实可以优化的,也耳熟能详(我真欠揍),我们只用从
2
2
2到
x
\sqrt x
x就可以了。
从 2 2 2到 x \sqrt x x的证明:
很容易发现这样一个事实:如果
a
a
a是
x
x
x的约数,那么
x
a
\frac{x}{a}
ax也是
x
x
x的约数。
得证。
代码:
bool is_prime(int x) {
for(int i=2;i<=sqrt(x);i++)
if(x%i==0) return 0;
return 1;
}
啊,其实还有更简单的判断方法: M i l l e r − R a b i n Miller-Rabin Miller−Rabin。耳熟能详个屁,自行学习吧。
素数筛法:
1. E r a t o s t h e n e s Eratosthenes Eratosthenes筛法
这
E
r
a
t
o
s
t
h
e
n
e
s
Eratosthenes
Eratosthenes一长串不是人读的是一个人的名字:埃拉托斯特尼。啊,耳熟能详。
E
r
a
t
o
s
t
h
e
n
e
s
Eratosthenes
Eratosthenes筛法的原理非常简单:一个素数的倍数一定不是素数。
代码:
void Eratosthenes(int n) {
for(int i=2;i<=n;i++) {
if(check[i]) continue;
prime[++cnt]=i;
for(int j=2;j<=n/2;j++)
check[i*j]=1;
}
return ;
}
过程如下:
正在处理的数 | 数组check的情况 |
---|---|
2 | 2,3, |
3 | 2,3, |
5 | 2,3, |
7 | 2,3, |
11 | 2,3, |
可以发现, 2 2 2和 3 3 3都会把 6 6 6标记为合数。实际上,小于x2的 x x x的倍数在之前就会被标记,所以我们可以优化为:
void Eratosthenes(int n) {
for(int i=2;i<=n;i++) {
if(check[i]) continue;
prime[++cnt]=i;
for(int j=i;j<=n/i;j++)
check[i*j]=1;
}
return ;
}
时间复杂度为 O ( n l o g l o g n ) O(n \ log \ log \ n) O(n log log n),显而易见。
线性筛法
埃式筛法也会重复标记,一个数的素数约数越多,重复标记越多。
我就不具体讲了,推荐一篇博客
代码:
void yu(int n) {
check[1]=1;
for(int i=2;i<=n;i++) {
if(!check[i]) prime[++cnt]=i;
for(int j=1;j<=cnt && i*prime[j]<=n;j++) {
check[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
return ;
}
啊,简单。