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 } } }