筛素数

整理一下筛素数的方法

我在网上了解到两种筛素数的方法

一种是  1/3n*判断  的时间复杂度

一种是的时间复杂度应该是比这个低

先说一下第一种的思路

首先:一个数如果他除以一个素数除不尽,那么他除以该素数的倍数也除不尽

所以我们可以这么考虑

如果一个数是二或三的倍数 那么它一定不是素数

于是 对于  1 2 3 4 5 6 7 8 9 10 11 12……

那么排除2和3的倍数

剩下的是 1 5 7 11 ……

对于六个数

6*n   6*n+1   6*n+2   6*n + 3   6*n + 4   6*n + 5

只需要检测 6*n+1 和6*n+5是不是素数就可以了

然后就是小的优化了

判断一个数x是不是素数

一种是枚举2~x-1  一种是2~sqrt(x) 都不是最优化的

由于之前已经存储了一些素数  可以枚举这些素数来判断  因为如果一个数除以一个素数除不尽  那么除以该素数的倍数一定除不尽

第二类有很多种优化

先写一下最原始的代码

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 using namespace std;
 6
 7 const int maxn = 105;
 8 int flag[maxn], prm[maxn];
 9
10 int get(int n) {
11     int k = 0;
12     memset(flag, 1, sizeof(flag));
13     for(int i = 2; i <= n; i++) {
14         if(flag[i]) {
15             prm[k++] = i;
16             for(int j = i; j <= n; j += i) {
17                 flag[j] = 0;
18             }
19         }
20     }
21     return k;
22 }
23
24 int main() {
25     int k = get(100);
26     for(int i = 0; i < k; i++) {
27         printf("%d ", prm[i]);
28     } puts("");
29 }

思路 是大一刚开学在杭电的一个题解上看到的

首先 2是素数 那么  2的倍数4 6 8……就一定不是素数

然后3是素数  那么 3的倍数也就一定不是素数

但是这种方法有很大的缺点

就是比如删除2的倍数的时候 会删到6 12 18等而删3的倍数的时候也会删到  于是造成了删除的冗余  所以该算法的执行效率一般

而接下来的优化全部都是对于这个方向的优化

第一中优化是来自一篇博客

他的思路是这样的

一个数如果不是素数那么他的因子一定有他小的素数

那么对于每个数i只要把i之前的所有素数都乘以i那么  就不会错过下一个数i+1是不是合数

这个方法应该能理解

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

const int maxn = 105;
int flag[maxn], prm[maxn];

int get(int n) {
    int k = 0;
    memset(flag, 1, sizeof(flag));
    for(int i = 2; i <= n; i++) {
        if(flag[i]) {
            prm[k++] = i;
        }
        for(int j = 0; j < k && prm[j] * i <= n; j++) {
            flag[prm[j] * i] = 0;
        }
    }
    return k;
}

int main() {
    int k = get(100);
    for(int i = 0; i < k; i++) {
        printf("%d ", prm[i]);
    } puts("");
}

还有一个优化  明早起来写

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 using namespace std;
 6
 7 const int maxn = 105;
 8 int flag[maxn], prm[maxn];
 9
10 int get(int n) {
11     int k = 0;
12     memset(flag, 1, sizeof(flag));
13     for(int i = 2; i <= n; i++) {
14         if(flag[i]) {
15             prm[k++] = i;
16         }
17         for(int j = 0; j < k && prm[j] * i <= n; j++) {
18             flag[prm[j] * i] = 0;
19             if(i % prm[j] == 0)
20                 break;
21         }
22     }
23     return k;
24 }
25
26 int main() {
27     int k = get(100);
28     for(int i = 0; i < k; i++) {
29         printf("%d ", prm[i]);
30     } puts("");
31 }

时间: 2024-10-09 17:39:22

筛素数的相关文章

常见模板(欧拉筛素数,最小生成树,快排,并查集,单源最短路)

欧拉筛素数: #include<cstdio> #define maxn 10000000+10 using namespace std; int n,prime[5000001],num_prime=0,m; bool if_prime[maxn]; void euler(int limit) { for(int i=2;i<=limit;i++) { if(!if_prime[i]) prime[++num_prime]=i; for(int j=1;prime[j]*i<=l

洛谷 P3383 【模板】线性筛素数

P3383 [模板]线性筛素数 题目描述 如题,给定一个范围N,你需要处理M个某数字是否为质数的询问(每个数字均在范围1-N内) 输入输出格式 输入格式: 第一行包含两个正整数N.M,分别表示查询的范围和查询的个数. 接下来M行每行包含一个不小于1且不大于N的整数,即询问概数是否为质数. 输出格式: 输出包含M行,每行为Yes或No,即依次为每一个询问的结果. 输入输出样例 输入样例#1: 100 5 2 3 4 91 97 输出样例#1: Yes Yes No No Yes 说明 时空限制:5

Poj2689筛素数

题目大意: 给定一个区间l,r,求这个区间内相邻的质数中最近的两个和最远的两个.区间范围是1-2^31,区间的长度最多是10^6. 思路: 刚开始对筛选法的理解不深,不知道如何筛选任意一段区间的素数,看了题解恍然大悟,原来用的筛选法总是筛选从1-n的素数,对于为何这样筛选理解不深刻.说下1-n的筛选法,就是用一个数组is_prime[1..n]标记1-n中哪个是素数哪个不是,从2(第一个素数)开始扫描,所有2的倍数都不是素数,那么下一个素数是谁?就是我们向后从is_prime[]中找到的第一个是

poj3126 筛素数+bfs

1 //Accepted 212 KB 16 ms 2 //筛素数+bfs 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <queue> 7 using namespace std; 8 const int inf = 100000000; 9 const int imax_n = 10005; 10 bool pri[imax_n]; 11 bool vi

睡前数学一小时之线性筛素数:

睡前数学一小时之线性筛素数:1,朴素的筛素数算法:埃拉托斯特尼筛法.这是个简单再简单不过的一个素数的筛法.只是名字很拉风.这就告诉我们,往往东西不好这没什么,名字很拉风.别人也不会记住.hhhhh.这个的思路就是.每一个数都是由一个质数与和数(质数也可以)的积组成.这也是质数与和数的定义.而这个它这个筛发,就是当遇到一个质数的时候开始枚举,枚举[1,n]中间关于这个质数的倍数.每次都枚举,每次都将算出的这个数打上标记.而最后整个区间内的质数枚举完后,整个区间内的质数也就筛选出来了.这个很简单.时

Hrbust1328 相等的最小公倍数 (筛素数,素因子分解)

本文出自:http://blog.csdn.net/svitter/ 题意: 求解An 与 An-1是否相等. n分为两个情况-- 1.n为素数, 2.n为合数. =  =好像说了个废话..素数的时候,可以直接输出no,因为素数不可能和An-1相等.合数的时候,如果n是a^b次方,那么也是NO.原因很简单,之前数字的最小公倍数的n的因子次方数,不能超过n的次方数. //================================================================

线性筛素数模板

传送门:线性筛素数 Prime: 1 #include<cstdio> 2 3 const int MAXN = 10000100; 4 int Prime[MAXN],n,m,Size; 5 bool Vis[MAXN]={1,1}; 6 7 int main() 8 { 9 scanf("%d%d",&n,&m); 10 for(int i=2;i<n;i++) 11 { 12 if(!Vis[i]) 13 Prime[++Size]=i; 14

leetcode 204. Count Primes(线性筛素数)

Description: Count the number of prime numbers less than a non-negative number, n. 题解:就是线性筛素数的模板题. class Solution { public: int countPrimes(int n) { int ans=0; vector<int>is_prime(n+1,1); for(int i=2;i<n;i++){ if(is_prime[i]){ ans++; for(int j=2*

poj 2635 The Embarrassed Cryptographer 筛素数+高精度除法

题意: 给K(<10^100),L(<10^6),求K小于L的最小素因子并输出,如果没有则输出GOOD. 分析: 枚举小于L的素数用高精度除法判断是否是因子,关键是怎么高效筛素数,先给一种比较慢的筛法: primes[max_prime_num],num=0; memset(vis,0,sizeof(vis)) for(int i=2;i<maxL;++i) if(vis[i]==0){ prime[num++]=i; for(int j=2*i;j<maxL;j+=i) vis[