再谈素数筛

关于素数筛我们介绍常用的两种素数筛:

普通筛法求素数:复杂度为O(nloglogn)

1 const int maxn = 100000;
2 bool vis[maxn];
3 memset(vis, false, sizeof(vis));
4 vis[1] = true;
5 for(int i = 2; i < maxn; ++i) if(!vis[i]){
6     for(int j = 2*i; j < maxn; j += i)
7         vis[j] = true;
8 }
9 //对于一个数n,若vis[n] == false 则n为素数,否则为合数

以上素数筛可以优化一下:

 

1 const int maxn = 100000;
2 bool vis[maxn];
3 memset(vis, false, sizeof(vis));
4 vis[1] = true;
5 int m = sqrt(maxn+0.5);
6 for(int i = 2; i <= m; ++i) if(!vis[i])
7     for(int j = i*i; j < maxn; j+=i)
8         vis[j] = true;
9 // 同样的,若vis[n] == false,则n为素数

 

欧拉筛(线性筛):复杂度为O(n)

 1 const int maxn = 100000;
 2 int primer[maxn], n = 0;
 3 bool vis[maxn];
 4 memset(vis, false, sizeof(vis));
 5 vis[1] = true;
 6 for(int i = 2; i < maxn; ++i) {
 7     if(!vis[i]) {
 8         primer[n++] = i;
 9     }
10     for(int j = 0; j < n; ++j) {
11         if(i * primer[j] >= maxn) {
12             break;
13         }
14         vis[i*primer[j]] = true;
15         if(i % primer[j] == 0) {
16             break;
17         }
18     }
19 }

上面这个算法保证了每个合数只会被它的最小质因子给筛去,所以算法复杂度就是O(n)

 

区间素数筛:

LightOJ - 1197 : https://vjudge.net/problem/LightOJ-1197

如果我们要统计区间[a, b], (1 <= a <= b <= 2^31) 之间的素数的个数,由于a,b的范围很大,但是b-a <= 100000,所以我们可以遍历这个区间内的所有数,判断它们是不是素数。判断一个数是不是素数,可以用O(√n)的算法,但是在这题行不通,我们可以借鉴素数筛的思想来解决这题。对于在区间[a,b]内的合数,它们的最小质因子一定是小于等于sqrt(b)的,所以我们可以先把1到sqrt(b)的所有素数求出来,再利用这些素数去筛掉[a,b]之间的合数。具体操作如下:

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 const int maxn = 70000;
 6 const int maxd = 100010;
 7 bool vis[maxn];
 8 bool primes[maxd];
 9 
10 // 打出1到2^16之间的素数
11 void init()
12 {
13     for(LL i = 2; i < maxn; ++i)if(!vis[i])
14         for(LL j = i*i; j < maxn; j+=i)
15             vis[j] = true;
16 }
17 
18 LL get_primes(LL a, LL b)
19 {
20     memset(primes, false, sizeof(primes));
21     if(a == 1) primes[0] = true;
22     LL m = sqrt(b+0.5);
23     for(LL i = 2; i <= m; ++i) if(!vis[i])
24     {
25         for(LL j = max(2LL, (a+i-1)/i)*i; j <= b; j+=i)
26             primes[j-a] = true;
27     }
28     LL ans = 0;
29     for(LL i = a; i <= b; ++i)
30         if(!primes[i-a]) ans++;
31     return ans;
32 }
33 
34 int main()
35 {
36     init();
37     int T, ca = 1;
38     scanf("%d", &T);
39     while(T--)
40     {
41         LL a, b;
42         scanf("%lld%lld", &a, &b);
43         LL ans = get_primes(a, b);
44         printf("Case %d: %lld\n", ca++, ans);
45     }
46     return 0;
47 }
View Code

 

 

 

 

 

 

posted @ 2018-08-06 19:10  DyastySun  阅读(165)  评论(0编辑  收藏  举报