素数筛的用处还是蛮多的,有很多和素数有关的题都要用到素数筛,所以有一个高效的筛法自然是非常好的吖,普通筛法(暴力筛法)就不说了,因为有了高效的也没人在会用普通筛法了吧。

  线性素数筛是用每一个合数的最小的质因数筛掉它,这个体现在代码里的  if(i%prime[j]==0)break;  这句话里,因为如果这里不跳出的话,j会继续向上枚举,这时i*peime[j]的最小的质因数是之前的那个prime[j]而不是现在的prime[j],而一旦出现这样的情况,就不能保证每个数都被自己最小的质因数筛掉。而加上了那句话之后,时间复杂度保证就是线性的。

  模板:https://www.luogu.org/problemnew/show/P3383

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 int n,m;
 5 bool vis[10000003];
 6 int prime[1000003];
 7 int cnt;
 8 int main()
 9 {
10     scanf("%d%d",&n,&m);
11     vis[0]=vis[1]=1;
12     for(int i=2;i<=n;++i)
13     {
14         if(!vis[i])prime[++cnt]=i;
15         for(int j=1;j<=cnt&&i*prime[j]<=n;++j)
16         {
17             vis[i*prime[j]]=1;
18             if(i%prime[j]==0)break; 
19         }
20     }
21     while(m--)
22     {
23         int x;
24         scanf("%d",&x);
25         if(!vis[x])printf("Yes\n");
26         else printf("No\n");
27     } 
28     return 0;
29 }
View Code

  还有一个叫做区间素数筛的东西,窝也是前几天才知道的,不过不是线性的,或许有线性的写法吧,不太会,但是复杂度也不是很高。

 1 #include<iostream>
 2 #include<cstdio>
 3 #define ll long long 
 4 using namespace std;
 5 const int maxn=1000005;
 6 bool b1[maxn],b2[maxn];
 7 ll prime[maxn];
 8 ll cnt;//区间素数筛的原理:(a,b)区间的合数的最小质因数一定小于sqrt(b),\
 9 //所以把2到sqrt(b)的素数筛出来,蓝后,用他们把他们在a到b的倍数筛出来 
10 int main()
11 {
12     ll a,b;
13     scanf("%lld%lld",&a,&b);b++;
14     for(ll i=0;i*i<b;++i)b2[i]=1;
15     for(int i=0;i<b-a;++i)b1[i]=1;
16     for(ll i=2;i*i<b;++i)
17     {
18         if(b2[i])
19         {
20             for(ll j=2*i;j*j<b;j+=i)b2[j]=0;
21             for(ll j=max(2ll,(a+i-1)/i)*i;j<b;j+=i)b1[j-a]=0;
22         }
23     }
24     for(ll i=0;i<b-a;++i)
25         if(b1[i])prime[cnt++]=a+i;
26     printf("%d\n",cnt);
27 }
View Code