质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数。
[ 1 , N ] [1,N] [1,N] 中的素数大概有 N / I n N N/InN N/InN 个
I.素数判断
首先,根据定义,我们可以枚举
(
1
,
n
)
(1,n)
(1,n) 里的数,若存在
i
i
i 使得
i
∣
n
i|n
i∣n ,
则
n
n
n 是合数,否则
n
n
n 是质数。
但其实不用枚举到
n
n
n , 因为
n
n
n 如果是合数,则其必定有一个小于等于
n
\sqrt{n}
n 的因子。
所以枚举到
[
n
]
[\sqrt{n}]
[n] 即可。
bool ifprime(LL x)
{
int i;
for(i=2;i*i<=x;i++)
if(x%i==0)
return false;
return true;
}
常数更小的筛法
把每一个数都表示成
6
x
+
y
,
(
x
,
y
∈
N
)
6x+y,(x,y\in N)
6x+y,(x,y∈N) 的形式。
那么有
- 6 x + 0 6x+0 6x+0 可以被 2,3,6 整除
- 6 x + 1 6x+1 6x+1 待定
- 6 x + 2 6x+2 6x+2 可以被 2 整除
- 6 x + 3 6x+3 6x+3 可以被 3 整除
- 6 x + 4 6x+4 6x+4 可以被 2 整除
- 6 x + 5 6x+5 6x+5 待定
先判断 n n n 能否被 2 , 3 2,3 2,3 整除(假定 n ≤ 4 n \le 4 n≤4)
- 若能则 n n n
bool isprime(LL x)
{
if(x==2||x==3) return 1;
if(x%6!=1&&x%6!=5) return 0;
for(int i=5;i*i<=x;i+=6)
if(x%i==0||x%(i+2)==0)
return 0;
return 1;
}
1.朴素筛法
时间复杂度 O ( n 3 / 2 ) O(n^3/2^) O(n3/2)
很容易想到从1枚举到n,挨个判断是不是素数;
Code:
void Prime()
{
int i,j;
for(i=2;i<=n;i++) {
if(ifprime(i))
pm[++tot]=i;
}
return;
}
## 2.Eratosthenes筛法
令A为素数,则A*N(N>1;N为自然数)都不是素数。
> 时间复杂度$O(nloglogn)$
##### Code:
```cpp
const LL N=1e7+5;
int pm[N];
bool tag[N];
int tot;
void Prime()
{
int i,j;
for(i=2;i<=n;i++) {
if(!tag[i])
pm[++tot]=i;
for(j=2;j<=i;j++) {
if(i*j>n) break;
tag[i*j]=true;
}
}
return;
}
3.线性筛法
在Eratosthenes筛法的基础上,让每个数最多被其最小质因数筛掉一次;
时间复杂度 O ( n ) O(n) O(n)
Code:
void Prime()
{
int i,j;
for(i=2;i<=n;i++) {
if(!tag[i])
pm[++tot]=i;
for(j=1;j<=tot;j++) {
if(i*pm[j]>n) break;
tag[i*pm[j]]=true;
if(i%pm[j]==0)
break;
}
}
return;
}