关于欧拉筛

背景:现在你需要尽快地找出1~n中的所有素数

0.1

一个朴素的想法,对于1到n中的i,我们从2~(i-1)遍历,如果在这之中找到了i的因子,i就不是素数

0.2

实际上,我们并不需要从2~(n-1)遍历,假设(m<n),那么一个合数i必然能写成m*n=i的形式,并且你发现m<=sqrt(i)<=n,也就是说,如果没有在sqrt(i)之前找到i的因子,sqrt(i)之后也不会有i的因子

0.3

看起来不错,可是对于每一个i,我们都需要做以上(0.2)的遍历,于是有了埃氏筛(每一个合数都有最小的质因子,那么我们就可以利用已经找到的素数,把这个素数的倍数筛去)

1.埃氏筛

#include <stdio.h>  
#include <stdbool.h> 

  
int main() {  
    bool Isprime[1000]={0}; //假设所有都是素数,好处就是不用再遍历赋值为1了
    int n,cnt=0;
    scanf("%d",&n);
    for(int i=2;i<=n;i++){
        if(~Isprime[i]){//素数赋值为0的后果
            for(int k=2;;k++){
                Isprime[k*i]=1;
                if(k*i>=n) break;
            }
        }
    }
    for(int i=2;i<=n;i++){//先排除0和1了,为了让i就对应具体的素数
        if(Isprime[i]==0) cnt++;
    }
    printf("%d",cnt);
    return 0;  
}

2.欧拉筛

不过虽然埃氏筛可以减少遍历个数,但是会存在反复标记合数的问题,于是我们引入欧拉筛,旨在规避反复标记的问题,即对于每个合数只能被它的最小质因子标记

如果要排除出从1~n的所有合数,我们模拟一下这种情形

假设现在遍历到i了,如果i是一个合数,那么i的质因子一定在2~i中,记为Pi,

对于Pi之前的所有质数Pj,有Pj*i=k,那么Pj一定是k的最小质因子,因为i的最小质因子为Pi>Pj,

同样的,对于Pi之后的素数Pn,若Pn*i=q,那么q的最小质因子一定不是Pn,这与欧拉筛的初宗相悖

也就是说,我们需要在素数遍历到Pi时,结束遍历

#include <stdio.h>  
#include <stdbool.h> 

  
int main() {  
    bool Ifprime[1000]={0}; //假设所有都是素数,好处就是不用再遍历赋值为1了
    int Isprime[1000];
    int n,cnt=0;
    scanf("%d",&n);
    for(int i=2;i<=n;i++){
        if(Ifprime[i]==0){//素数赋值为0的后果
            Isprime[++cnt]=i;
            //Isprime[cnt++]=i;
            //这是笔者最初的版本,后果就是cnt领先于目前的素数数目
            //导致后面除数为0
            for(int k=1;k<=cnt;k++){
                if(Isprime[k]*i<=n)
                Ifprime[i*Isprime[k]]=1;
                else break;
                if(i%Isprime[k]==0) break;
            }
        }
    }
    printf("%d",cnt);
    return 0;  
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值