首页 > 其他分享 >素数的判定:筛法

素数的判定:筛法

时间:2023-10-09 22:55:07浏览次数:44  
标签:埃氏 筛法 int 质数 素数 判定 isPrime include 合数

素数很有用,特别是在密码学领域中,比如RSA中很重要的一步就是寻找两个比较大的素数,通常的做法是先随机生成一个大整数,然后使用一些素性判定的方法,比如费马素性测试。在算法竞赛的数论题目中,素数也很常见,通常的做法是先找出一定范围内的所有素数,用到时再查表,筛法就可以做到。

1. 埃氏筛

埃拉托斯特尼筛法,简称埃氏筛。埃氏筛的原理是直观的,基于这样一个事实:素数不能被任意比它小的、除1以外的数整除;合数一定存在一个比它小且不为1的数整除。从2开始,当能确定一个数是质数时,就可以把这个数的整数倍标记为合数。从小到大遍历到一个数,如果它依然没有被标记为合数,那么就能确定它是质数。筛法中用到的数只有质数,筛选的对象是合数。这样做可以减少操作次数,并且可以筛掉所有的合数。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
bool isPrime[100000010];
//isPrime[i] == 1表示i是素数
int Prime[60000010], cnt;
//Prime存质数
int n, q, k;

void GetPrime(int n) {
    memset(isPrime, true, sizeof(isPrime));
    isPrime[1] = false;
    isPrime[2] = true;
    for(int i = 2; i <= n; i ++) {
        if(isPrime[i]) {
            Prime[cnt ++] = i;
            for(int j = 2; i * j <= n; j ++) {
                isPrime[i * j] = false;
            }
        }
    }
}

2. 欧拉筛

埃氏筛存在重复筛的情况,欧拉筛可以保证范围内的每个合数都被筛掉,并且任一合数只被最小质因数筛掉,也就是只被筛一次。欧拉筛的时间复杂度为O(n),因此也被成为线性筛。
先来看一下代码。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
bool isPrime[100000010];
//isPrime[i] == 1表示i是素数
int Prime[60000010], cnt;
//Prime存质数
int n, q, k;

void GetPrime(int n) {
    memset(isPrime, true, sizeof(isPrime));
    isPrime[1] = false;
    isPrime[2] = true;
    for(int i = 2; i <= n; i ++) {
        if(isPrime[i]) {
            Prime[cnt ++] = i;
        }

        for(int j = 0; j < cnt && i * Prime[j] <= n; j ++) {
            isPrime[i * j] = false;
            if(i % Prime[j] == 0) {
                break; //保证只被“最小质因数 × 最大因数(非自己) = 这个合数”筛掉
            }
        }
    }
}

线性筛的代码和埃氏筛很相似,比较明显的不同有两处,埃氏筛中的i一定是质数,而线性筛的i是小于等于n的所有数,Prime[j]一定是质数;另一个不同就是线性筛的条件判定提前结束内层循环。我们知道欧拉筛的线性时间复杂度是因为合数只被筛一次,也就是“最小质因数 × 最大因数(非自己) = 这个合数”,条件判定提前结束就保证了这件事。举一个例子,使用埃氏筛,30会被2(*15)、3(*10)和5(*6)筛三次,在线性筛中i依次遍历到2,3,5的时候是不可能筛掉30的,因为i只和小于自己的质数相乘,i遍历到6时,因为6能整除2,所以只会筛掉12,而不会筛掉和3、5相乘得到的18、30,这是因为对于30而言可以分解为6*5,而6可以整除2的话,那么必然可以将2分给5得到一个更大的数,也就是10,所以要结束。

参考资料

  1. 埃氏筛、欧拉筛详解

标签:埃氏,筛法,int,质数,素数,判定,isPrime,include,合数
From: https://www.cnblogs.com/zhangdoudou/p/17753410.html

相关文章

  • Go 语言代码示例。使用并发和通道的并行计算素数的示例代码
    Go语言代码示例。使用并发和通道的并行计算素数的示例代码:packagemainimport( "fmt")funcmain(){ lowerLimit:=2 upperLimit:=100 //创建管道,用于在协程之间传递素数 primes:=make(chanint) //创建一个协程来生成素数序列 gogeneratePrimes(primes)......
  • 筛法求约数个数
    推荐视频:516筛法求约数个数点击查看代码#include<bits/stdc++.h>usingnamespacestd;#defineLLlonglongconstintN=1e8+10;intp[N],cnt;intd[N];//d[i]记录i的约数的个数inta[N];//a[i]记录i的最小质因子的次数boolvis[N];voidget_d(intn){//筛法求......
  • 【模板】线性筛素数
    【模板】线性筛素数点击查看代码#include<bits/stdc++.h>usingnamespacestd;#defineLLlonglongconstintN=1e8+10;intp[N],cnt,vis[N];intmain(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); intn,q; cin>>n>>q; for(inti=2;i......
  • linux磁盘空间满了后怎么去判定哪个地方占了多大的空间并回收
    概述日常工作总会碰到磁盘满的情况,这时候我们需要去判定哪个地方占的存储比较多,看那些文件有没用,如果没用就可以删掉节省空间。下面大概写一下处理的一个过程。1、使用df-h查看磁盘空间占用情况 2、使用du-s/*|sort-nr命令查看那个目录占用空间大 然后那个......
  • 数学筛法
    有的时候怕忘记,写篇小博客记录一下。线性筛素数inlinevoidinit(intn){for(inti=2;i<=n;i++){if(!vis[i])prime[++cnt]=i;for(intj=1;j<=cnt&&i*prime[j];j++){vis[i*prime[j]]=1;if(!(i%prime[j]))br......
  • 素数重学笔记
    之前都没有怎么理解,现在来复习一下。试除法从\(2\)枚举到\(\lfloor\sqrtn\rfloor\)判断能否整除。朴素筛法从小到大枚举每个数,将范围内它的倍数全部标记为合数。显然就是调和级数,时间复杂度\(O(n\logn)\)。埃氏筛观察到一个合数必定可以通过某个质数乘上一个数得到......
  • 素数—埃式筛法
    埃式筛法思路 利用当前已经确定的素数筛选掉非素数的自然数,然后向后选择没有被筛选的自然数,即素数,重复上述操作。实现打印[1,100]区间的素数#include<iostream>#include<vector>usingnamespacestd;intmain(){vector<int>prime;vector<bool>isPrime(11......
  • 素数判定的C语言程序
    ```c#include<stdio.h>intmain(void){  inti,n;  printf("请输入一个数字:");  scanf_s("%d",&n);  for(i=2;i<n;i++)    if(n%i==0)      break;  if(i<n)    printf("%disdivi......
  • Java学习_005 if语句:奇偶数的判定
    需求:任意给出一个整数,使用程序判定该整数是奇数还是偶数,并在控制台输出。1importjava.util.Scanner;23publicclassMain{4publicstaticvoidmain(String[]args){5Scannersc=newScanner(System.in);6System.out.println("please......
  • 素数打表
    #defineN50000//质数范围intprime[1000000];//prime[0]=2,prime[1]=3,prime[2]=5,……voidinit_prime(){inti,j;for(i=2;i<=sqrt(N*1.0);++i){if(!prime[i])for(j=i*i;j<N;j+=i)......