首页 > 代码库 > 关于欧拉筛筛素数

关于欧拉筛筛素数

观察如下欧拉筛代码:

 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,故该筛的早已筛了,现在主要是记录质数,但流程还得继续啊)

关于欧拉筛筛素数