素数筛

柔情痞子 提交于 2020-03-29 15:51:59

1.(nlogn):

bool not_prime[2333]=false;
//把非质数都设为false,如果not_prime为false,则是质数,为true,则不是质数
not_prime[1]=true;
for(int a=2;a<=n;a++)
    for(int b=a+a;b<=n;b+=a)
        not_prime[b]=true;
//是a的倍数的数b全部是非质数,即not_prime[b]=true;
/*b从2a开始,每次+a,直到题目给定的范围n结束
a=2的时候,b一共+n/2次
a=3的时候,b一共+n/3次
...
a=n的时候,b一共+n/n次
那么整体时间复杂度就是:
n*(n/2+n/3+...+n/n)
≈n*(n/1+n/2+n/3+...+n/n)
≈nlogn
注:n/1+n/2+n/3+...+n/n为调和级数,其值约为logn,有兴趣自查*/

/*我们知道,筛4的时候,4的倍数已经在2中筛完了
筛6的时候,6的倍数已经在3中筛完了
以此类推,合数的倍数将在前面筛完了
那么我们就有如下小优化:*/

bool not_prime[2333]=false;
not_prime[1]=true;
for(int a=2;a<=n;a++)
    if(not_prime[a]==false)
        for(int b=a+a;b<=n;b+=a)
        not_prime[b]=true;

当然,即使优化后也会有被多次筛掉的部分,比如6就被2,3都筛过一遍

那么我们引出下面的线性筛

2.线性筛 O(n)

若有x=p1^r1*pr2^r2*...*pk^rk,p1<p2<...<pk

那么我们希望每一个数被筛掉的时候都是用它最小的质因子筛掉的

这样只会被筛掉一次

//线性筛(xxs-小学生) 

int prime[233],pcnt//pcnt代表几个质数 
bool not_prime[23333];
void xxs(int n)
{
    not_prime[1]=true;
    for(int a=2;a<=n;a++)
    {
        if(not_prime[a]==false)
            prime[++pcnt]=a;//若a是质数,把a存下来
        for(int b=1;b<=pcnt;b++)
        {
            int v=a*prime[b];//v表示a的质数倍
            //可以理解为:要把prime[b]这个质数的a倍筛掉 
            if(v>n)
                 break;//如果v枚举到大于n了,跳出循环
            not_prime[v]=true;//v设为非质数
            if(a%prime[b]==0)
                break;
            //如果a是prime[b]的倍数,那么prime[b+1]*a也一定是prime[b]的倍数
            //所以能筛掉prime[b+1]*a的最小质数不是prime[b+1],而是prime[b] 
            //由于想要让每个合数被最小的质数筛掉 
            //那么能筛掉a*prime[b]的最小质数就是prime[b]
            //所以如果a%prime[b]==0,直接break 
        }
    }
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!