[算法]素数筛法

【方法一】

【代码一】

[cpp] view
plain
copy

  1. //判断是否是一个素数
  2. int IsPrime(int a){
  3. //0,1,负数都是非素数
  4. if(a <= 1){
  5. return 0;
  6. }
  7. //计算枚举上界,为防止double值带来的精度损失,所以采用根号值取整后再加1,即宁愿多枚举一个,也不愿少枚举一个数
  8. int bound = (int)sqrt(a) + 1;
  9. for(int i = 2;i < bound;i++){
  10. //依次枚举这些数能否整除x,若能则必不是素数
  11. if(a % i == 0){
  12. return 0;
  13. }
  14. }
  15. return 1;
  16. }

【方法二】

【代码二】

[cpp] view
plain
copy

  1. #define MAXSIZE 10001
  2. int Mark[MAXSIZE];
  3. int prime[MAXSIZE];
  4. //判断是否是一个素数  Mark 标记数组 index 素数个数
  5. int Prime(){
  6. int index = 0;
  7. memset(Mark,0,sizeof(Mark));
  8. for(int i = 0;i < MAXSIZE;i++){
  9. //已被标记
  10. if(Mark[i] == 1){
  11. continue;
  12. }
  13. else{
  14. //否则得到一个素数
  15. prime[index++] = i;
  16. //标记该素数的倍数为非素数
  17. for(int j = i*i;j < MAXSIZE;j += i){
  18. Mark[j] = 1;
  19. }
  20. }
  21. }
  22. return index;
  23. }

【方法三】

这种方法比较好理解,初始时,假设全部都是素数,当找到一个素数时,显然这个素数乘上另外一个数之后都是合数

把这些合数都筛掉,即算法名字的由来。但仔细分析能发现,这种方法会造成重复筛除合数,影响效率。

比如10,在i=2的时候,k=2*15筛了一次;在i=5,k=5*6 的时候又筛了一次。所以,也就有了快速线性筛法。

【代码三】

[cpp] view
plain
copy

  1. int Mark[MAXSIZE];
  2. int prime[MAXSIZE];
  3. //判断是否是一个素数  Mark 标记数组 index 素数个数
  4. int Prime(){
  5. int index = 0;
  6. memset(Mark,0,sizeof(Mark));
  7. for(int i = 2; i < MAXSIZE; i++)
  8. {
  9. //如果未标记则得到一个素数
  10. if(Mark[i] == 0){
  11. prime[index++] = i;
  12. }
  13. //标记目前得到的素数的i倍为非素数
  14. for(int j = 0; j < index && prime[j] * i < MAXSIZE; j++)
  15. {
  16. Mark[i * prime[j]] = 1;
  17. if(i % prime[j] == 0){
  18. break;
  19. }
  20. }
  21. }
  22. return index;
  23. }

利用了每个合数必有一个最小素因子。每个合数仅被它的最小素因子筛去正好一次。所以为线性时间。

代码中体现在:

if(i%prime[j]==0)break;

prime数组 中的素数是递增的,当 i 能整除 prime[j],那么 i*prime[j+1] 这个合数肯定被 prime[j] 乘以某个数筛掉。

因为i中含有prime[j], prime[j] 比 prime[j+1] 小。接下去的素数同理。所以不用筛下去了。

在满足i%prme[j]==0这个条件之前以及第一次满足改条件时,pr[j]必定是pr[j]*i的最小因子。

参考博文:点击打开链接

习题练习:点击打开链接

时间: 2024-10-22 02:41:30

[算法]素数筛法的相关文章

素数专题——素数筛法

关于素数的判断,大家最常用的方法估计就是循环判断到sqrt(n)的方法了:(直接上代码) bool isprime(int n) { for(int i=2;i<=sqrt(n);i++) { if(n%i==0) return false; } return true; } 这种素数的判断方法的确直观,但这种算法只对较小数据量适用,当数据量较大时,该方法就不再适用于素数的判定了.因此,我们此处引入一种新的算法——素数筛法. 首先介绍一下什么叫素数筛法: 假设所有待判断的数字的上限是L,声明一个

素数筛法—时间复杂度O(n)

请你想出一个算法求出n以内(含n)的所有素数,要求算法的时间复杂度越小越好. 这里介绍一种算法--快速线性素数筛法(欧拉筛法),时间复杂度O(n). 诀窍在于:筛除合数时,保证每个合数只会被它的最小质因数筛去.因此每个数只会被标记一次,所以算法时间复杂度为O(n). 具体请看下面的代码,主要函数是Prime(n). 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 vector<int> Prime(int n) { /

hdu6069[素数筛法] 2017多校3

/*hdu6069[素数筛法] 2017多校3*/ #include <bits/stdc++.h> using namespace std; typedef long long LL; LL l, r, k; const LL MOD = 998244353LL; int T, n, prime[1100000], primesize; bool isprime[11000000]; void getlist(int listsize) { memset(isprime, 1, sizeof

POJ_3421_X-factor Chains(素数筛法)

X-factor Chains Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5659   Accepted: 1786 Description Given a positive integer X, an X-factor chain of length m is a sequence of integers, 1 = X0, X1, X2, -, Xm = X satisfying Xi < Xi+1 and Xi

HDU 6069 Counting Divisors(区间素数筛法)

题意:...就题面一句话 思路:比赛一看公式,就想到要用到约数个数定理 约数个数定理就是: 对于一个大于1正整数n可以分解质因数: 则n的正约数的个数就是 对于n^k其实就是每个因子的个数乘了一个K 然后现在就变成了求每个数的每个质因子有多少个,但是比赛的时候只想到sqrt(n)的分解方法,总复杂度爆炸,就一直没过去,然后赛后看官方题解感觉好妙啊! 通过类似素数筛法的方式,把L - R的质因子给分解,就可以在O(nlogn)的时间之内把所以的数给筛出来. 代码: /** @xigua */ #i

poj 2478 Farey Sequence(基于素数筛法求欧拉函数)

http://poj.org/problem?id=2478 求欧拉函数的模板. 初涉欧拉函数,先学一学它基本的性质. 1.欧拉函数是求小于n且和n互质(包括1)的正整数的个数.记为φ(n). 2.欧拉定理:若a与n互质,那么有a^φ(n) ≡ 1(mod n),经常用于求幂的模. 3.若p是一个质数,那么φ(p) = p-1,注意φ(1) = 1. 4.欧拉函数是积性函数: 若m与n互质,那么φ(nm) = φ(n) * φ(m). 若n = p^k且p为质数,那么φ(n) = p^k - p

NowCoder猜想(素数筛法+位压缩)

在期末被各科的大作业碾压快要窒息之际,百忙之中抽空上牛客网逛了逛,无意中发现一道好题,NowCoder猜想,题意很明显,就是个简单的素数筛法,但竟然超内存了,我晕(+﹏+)~  明明有 3 万多 k 的空间限制……于是我不打表,试了试最暴力的做法,赤裸裸的做法果然超时了,无奈,只好对素数筛法进行位压缩了,这是我目前所能想到的方法了,第一次用上这样的特技,还是调了好一会(位数组里不能用 bool 来定义,具体的话好像 bool 和 int 之类的整型稍有不同:也不能用 int,因其最高位是正负标志

【POJ3006】Dirichlet&#39;s Theorem on Arithmetic Progressions(素数筛法)

简单的暴力筛法就可. 1 #include <iostream> 2 #include <cstring> 3 #include <cmath> 4 #include <cctype> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <numeric> 9 using namespace std; 10 11 co

HDOJ 6069 素数筛法(数学)

Counting Divisors Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 3041    Accepted Submission(s): 1130 Problem Description In mathematics, the function d(n) denotes the number of divisors of