字母不能映射成0
P 131 13331
素数筛法
优化版埃氏筛法(调和级数+质数定理=NloglogN)
质数定理:1-n中有 n ln n \frac{n}{\ln n} lnnn个质数
优化后的筛法可以减少大量的重复筛,只需要将质数的倍数筛掉(算术基本定理(正整数的唯一分解定理):每个大于1的自然数,要么本身就是质数,要么可以写为2个或以上的质数的积,而且这些质因子按大小排列之后,写法仅有一种方式。)但是仍然无法做到所有数只筛一次。
例
如
:
3
∗
35
=
7
∗
15
=
105
,
i
=
3
时
,
j
=
3
∗
3
j
=
3
∗
3
+
3
∗
2
j
=
3
∗
3
+
3
∗
2
+
3
∗
2
=
3
∗
3
+
3
∗
4
.
.
.
.
.
.
.
j
=
3
∗
3
+
3
∗
32
=
3
∗
35
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
当
i
=
7
时
j
=
7
∗
7
j
=
7
∗
7
+
7
∗
2
.
.
.
.
.
.
.
.
.
.
.
.
j
=
7
∗
7
+
7
∗
8
=
7
∗
15
此
处
重
复
筛
了
105
这
个
数
例如:3*35=7*15=105,\\ i=3时,\\ j=3*3\\ j=3*3+3*2 \\ j=3*3+3*2+3*2=3*3+3*4\\ .......\\ j=3*3+3*32=3*35\\ \\ ------------------\\ 当i=7时\\ j=7*7\\ j=7*7+7*2\\ ............\\ j=7*7+7*8=7*15\\ 此处重复筛了105这个数
例如:3∗35=7∗15=105,i=3时,j=3∗3j=3∗3+3∗2j=3∗3+3∗2+3∗2=3∗3+3∗4.......j=3∗3+3∗32=3∗35−−−−−−−−−−−−−−−−−−当i=7时j=7∗7j=7∗7+7∗2............j=7∗7+7∗8=7∗15此处重复筛了105这个数
bool primer[N];//[0,N],合数值为1,素数为0,素数定义为大于1的自然数中
void find_primer(int N){
int sqr=sqrt(N);
for(int i=4;i<N;i+=2)primer[i]=1;//2的倍数标记为合数
for(int i=2;i<=sqr;i++){
if(!primer[i])
for(int j=i*i;i<=N;j+=i*2)//j从i*i开始,i*(k)(k=2,3,,,,(i-1))已经被(k)筛过了,
primer[j]=1; //i(素数)和j都为奇数,j+i为偶数,故为j+2i;
}
}
欧拉筛法(O(N) 最小质因子的应用)
每个合数有一个最小质因子,只被最小质因子筛去过一次,故为线性时间。
假设primer[j]
简写为pj
;
i
%
p
r
i
m
e
r
[
j
]
=
=
0
i \% primer[j]==0
i%primer[j]==0时,由于primer[]
是按从小到大的顺序排列的,碰到的第一个质数就是最小质因子。此时应该break
跳出循环,若继续筛下去,下一个数为:
i
∗
p
r
i
m
e
r
[
j
+
1
]
=
k
∗
p
r
i
m
e
r
[
j
]
∗
p
r
i
m
e
r
[
j
+
1
]
p
r
i
m
e
r
[
j
]
∗
i
′
i*primer[j+1]\\=k*primer[j]*primer[j+1]\\primer[j]*i'
i∗primer[j+1]=k∗primer[j]∗primer[j+1]primer[j]∗i′
会在当 i i i过更大的时候筛去。
bool vis[N];//标记非素数,
int primer[N];//存素数
int cnt=0;//记录素数个数,
void find_primer(int N){
for(int i=2;i<=N;i++){
if(!vis[i])primer[cnt++]=i;
for(int j=0;j<cnt&&primer[j]*i<=N;j++){
vis[i*primer[j]]=1;//筛
if(i%primer[j]==0)break;//关键!!!找到i*primer[j]的最小质因子primer[j],退出
}
}
}
欧拉筛法打表观察:
for (int i = 2;i <= maxn; i++) {
cout<<" i = "<<i<<endl;
if (!visit[i])
prime[++prime[0]] = i; //纪录素数, 这个prime[0] 相当于 cnt,用来计数
for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++) {
cout<<" j = "<<j<<" prime["<<j<<"]"<<" = "<<prime[j]<<" i*prime[j] = "<<i*prime[j]<<endl;
visit[i*prime[j]] = 1;
if (i % prime[j] == 0) break;
}
}
i = 8 ,j = 1,prime[j] = 2,如果不跳出循环,prime[j+1] = 3,8*3 = 2*4*3 = 2*12,在i = 12时会计算。因为欧拉筛法的原理便是通过最小素因子来消除。