首页 > 代码库 > 关于欧拉筛筛素数
关于欧拉筛筛素数
观察如下欧拉筛代码:
1 const int MAXN=30000001; 2 int prime[MAXN]; 3 bool vis[MAXN]; 4 int Prime(int n){ 5 int cnt=0; 6 memset(vis,0,sizeof(vis)); 7 for(int i=2;i<n;i++){ 8 if(!vis[i]) 9 prime[cnt++]=i;10 for(int j=0;j<cnt&&i*prime[j]<n;j++){11 vis[i*prime[j]]=1;12 if(i%prime[j]==0)13 break;14 }15 }16 return cnt;17 }
发现其流程如下:
- 从1至n枚举,对于元素i:
- 判断其是否已被筛除?否,则已经确定其为质数
- 枚举不大于i的最小质因子的质数:
- 将i与这些质数的乘积筛除;
充分性:
——为什么流程第2行是正确的呢?
任意合数k可表示为其 最小质因子pj 与 数i 相乘(i:质数or合数)
且pj小于等于 数i 的最小质因子(否则该质因子才是k的最小质因子)
所以只要数i被枚举,合数k即被筛除(见流程3,4行)
由于i一定小于k,故当枚举到合数k时,她已经被删除啦(见流程1行)
即,该流程满足使所有合数被数i与该合数最小质因子pj相乘的情况筛去
效率:
——为什么这样快?
在流程中,统计筛操作的次数:
由于合数k只被数i与该合数最小质因子pj相乘的情况筛去
(当另一个数l想要与k的另一个大点的质因子pm筛去k时,她惊奇地发现她的最小质因子比pm大——因为pj正是她的最小质因子——这就意味着她不能筛k)
所以所以合数只被筛了一次;
视为O(n)的效率
附上一个筛数的流程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
枚举至2,并筛除:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
质数:2;
枚举至3,并筛除:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
质数:2,3;
枚举至4,并筛除:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
质数:2,3;
枚举至5,并筛除:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
质数:2,3,5;
枚举至6,并筛除:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
质数:2,3,5;
枚举至7,并筛除:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
质数:2,3,5,7;
然后重复以上过程,筛除,并记录质数;
(由于最小质数2,与8相乘已经大与15,故该筛的早已筛了,现在主要是记录质数,但流程还得继续啊)
关于欧拉筛筛素数