zoukankan      html  css  js  c++  java
  • 再谈素数筛

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

    普通筛法求素数:复杂度为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
    ", ca++, ans);
    45     }
    46     return 0;
    47 }
    View Code

     

  • 相关阅读:
    VUE.js入门学习(2)-基础精讲
    VUE中的MVVM模式
    VUE.js入门学习(1)-起步
    Vuex 是什么
    Proxy
    VUE常见的语法
    ES6的一些语法
    Element
    Mock.js
    第一阶段:Python开发基础 day14 三元表达式 生成器 匿名函数
  • 原文地址:https://www.cnblogs.com/DynastySun/p/9432030.html
Copyright © 2011-2022 走看看