今天我们来谈一谈素数的判定/筛法。

对于每一个OIer来说,在漫长的练习过程中,素数不可能不在我们的眼中出现,那么判定/筛素数也是每一个OIer应该掌握的操作,那么我们今天来分享几种从暴力到高效的判定法/筛法。

弱智的譬如从1枚举到n或者是枚举的\(\sqrt{n}\)的算法就不讲了。


1.欧拉筛

欧拉筛是最基本的一种线性筛法,预处理完成之后可以O(1)查询,适合于查询次数多,范围不大的情况。

基本思想:每个合数只让其最大因数(或最小质因数)标记。

为了保证这一点,我们开一个prime数组,把检查到的质数按顺序放入。其作用是对于枚举到的数\(i\) ,可依次乘上

prime数组中元素来标记合数;在标记过程中,如果\(prime[j]|i\) ,则停止这轮标记。

预处理部分:

for(int i=2;i<=n;i++)
{
if(!book[i])prime[++ind]=i;
for(int j=1;j<=ind;j++)
{
if(i*prime[j]>n) break;
book[i*prime[j]]=1;
if(!i%prime[j])break;
}
}

预处理完成之后,\(prime[i](i \leq ind)\)表示一个n以内的质数。

注意:最好不要用这里的\(book[i]\)直接判断输出,会惊起WA声一片da!


2.另一种方法

因为不知道叫什么名字所以先这样吧...

这个判定方法有点玄学...给大家推一下。

证明:令x≥1,将大于等于5的自然数表示如下:

······ 6x-1,6x,6x+1,6x+2,6x+3,6x+4,6x+5,6(x+1),6(x+1)+1 ······

明显可以看到,不在6的倍数两侧,即6x两侧的数为6x+2,6x+3,6x+4,由于2(3x+1),3(2x+1),2(3x+2),所以它们一定不是素数,再除去6x本身,显然,素数要出现只可能出现在6x的相邻两侧。这里要注意的一点是,在6的倍数相邻两侧并不一定就是质数

此时判断质数可以以6为单位快进,即将方法(2)循环中i++步长加大为6,加快判断速度,原因是,假如要判定的数为n,则n必定是6x-1或6x+1的形式,对于循环中6i-1,6i,6i+1,6i+2,6i+3,6i+4,其中如果n能被6i,6i+2,6i+4整除,则n至少得是一个偶数,但是6x-1或6x+1的形式明显是一个奇数,故不成立;另外,如果n能被6i+3整除,则n至少能被3整除,但是6x能被3整除,故6x-1或6x+1(即n)不可能被3整除,故不成立。综上,循环中只需要考虑6i-1和6i+1的情况,即循环的步长可以定为6,每次判断循环变量k和k+2的情况即可。

代码实现也很简单,不过需要注意的是有两种情况需要特判:

1.这个数是1,需要返回false;

2.这个数是2或3,需要返回true;

其他的按照上面的思路打出来就对了,代码如下:

bool isPrime_3(int num)
{
if(num==1)
return 0;
if(num==2||num==3)
return 1;
if(num%6!=1&&num%6!=5)
return 0;
int tmp=sqrt(num);
for(int i=5;i<=tmp;i+=6)
if(num%i==0||num%(i+2)==0)
return 0;
return 1;
}

这种判断的方法的速度应该算是很快了,判断\(40W\)个数是否是素数只需要\(0.099s\)。

3.Miller-Rabin判断法

这个方法骑士我没有过多地进行了解,但是据说它很玄学!

代码也比较复杂

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll qpow(ll x,ll y,ll p)//x^y mod p
{
ll ans=1,m=x;
while(y)
{
if(y&1)ans*=m;
ans%=p;
m*=m;
m%=p;
y>>=1;
}
return ans;
}
bool check(ll x,ll y,ll p)
{
ll q=qpow(x,y,p);
if(q!=1&&q!=p-1)return 0;
if(q==p-1)return 1;
if(q==1&&(y&1))return 1;
return check(x,y>>1,p);
}
bool mil(ll x)
{
if(x<=1)return 0;
if(x==2||x==7||x==61||(check(2,x-1,x)&&check(7,x-1,x)&&check(61,x-1,x)))/*底数RP++*/return true;
return 0;
}
int main()
{
int n,m;
ll k;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>k;
if(mil(k))cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}

很明显,mil函数中第二个if里面的数字是可以修改的,也决定了你的正确率(最好选择素数)

如果选择\(2,3\)作为这个底,可以通过130w以内的数据,如果用\(2,7,61\)作为底,可以通过4.7亿以内的数据(真的玄学)

当然,如果选其他的质数作为底,错误率也很低,只有\(4^{-k}\)

其他的就不多讲了吧...以后深入了解了之后可能会更新。

ov.

【素数判定/筛法进阶算法】-C++的更多相关文章

  1. 10^9以上素数判定,Miller_Rabin算法

    #include<iostream> #include<cstdio> #include<ctime> #include<string.h> #incl ...

  2. 梅森素数 判定总结 - Lucas-Lehmer算法 & Miller-rabin算法

    梅森素数 定义: if m是一个正整数 and 2^m-1是一个素数 then m是素数 if m是一个正整数 and m是一个素数 then M(m)=2^m-1被称为第m个梅森数 if p是一个素 ...

  3. 公钥密码之RSA密码算法大素数判定:Miller-Rabin判定法!

    公钥密码之RSA密码算法大素数判定:Miller-Rabin判定法! 先存档再说,以后实验报告还得打印上交. Miller-Rabin大素数判定对于学算法的人来讲不是什么难事,主要了解其原理. 先来灌 ...

  4. FZU 1649 Prime number or not米勒拉宾大素数判定方法。

    C - Prime number or not Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & % ...

  5. 数学#素数判定Miller_Rabin+大数因数分解Pollard_rho算法 POJ 1811&2429

    素数判定Miller_Rabin算法详解: http://blog.csdn.net/maxichu/article/details/45458569 大数因数分解Pollard_rho算法详解: h ...

  6. Miller-Rabin算法 codevs 1702 素数判定 2

    转载自:http://www.dxmtb.com/blog/miller-rabbin/ 普通的素数测试我们有O(√ n)的试除算法.事实上,我们有O(slog³n)的算法. 定理一:假如p是质数,且 ...

  7. Miller_Rabin()算法素数判定 +ollard_rho 算法进行质因数分解

    //****************************************************************// Miller_Rabin 算法进行素数测试//速度快,而且可以 ...

  8. [算法]Miller-Robbin素数判定

    目录 一.实现原理 二.应用 判断一个正整数是否为素数 三.小结 一.实现原理 我们以前都是怎么判断素数的呢: 试除法: 若一个正整数N为合数,则存在一个能整除N的数k,其中\(2\leqslant ...

  9. 有关素数判断的一些算法(总结&&对比)

    素性测试是数论题中比较常用的一个技巧.它可以很基础,也可以很高级(哲学).这次主要要介绍一下有关素数判断的奇技淫巧 素数的判断主要分为两种:范围筛选型&&单个判断型 我们先从范围筛选型 ...

随机推荐

  1. Python——raise引发异常

    程序出现错误,会自动引发异常,Python也允许使用raise语句自行引发异常. 一.使用raise引发异常 单独一个raise引发异常,默认引发RuntimeError异常,例: try: prin ...

  2. vim常用命令的使用

    中文博客:https://www.cnblogs.com/lijia0511/p/5644566.html 英文原文:http://yannesposito.com/Scratch/en/blog/L ...

  3. 写Markdown博客时遇到的一些问题

    成对的美元符号$,无法转义 相同的文本,就因为成对的$(美元符号),上面显示成了公式(Math)-而且还无法转义!下面用单行代码(``)-键盘"1"左侧的键,显示就正常了 下图方法 ...

  4. PB笔记之验证必填(pfc_validation)

    pfc_validation事件中可以在保存时进行提示

  5. window服务器查看管理员列表

    快捷键win+R 输入cmd并进入 输入指令net localgroup administrators

  6. 音视频入门-13-使用开源库生成PNG图片

    * 音视频入门文章目录 * RGB-to-PNG 回顾 上一篇 [手动生成一张PNG图片] 根据 [PNG文件格式详解] 一步一步地手动实现了将 RGB 数据生成了一张 PNG 图片. 有许多开源的 ...

  7. hdu1171 灵活的运用背包问题咯。。。 还有!!!! 合理的计算数组的范围!! wa了好多次!

    Problem Description Nowadays, we all know that Computer College is the biggest department in HDU. Bu ...

  8. SQL Sever 刪除重複數據只剩一條

    use book go create table ##T1( n int, a nvarchar(20) ) --查詢重複記錄,插入臨時表 insert into ##T1(n,a) select s ...

  9. hibernate注解(自动建表如何有表DDL注释) -- Comment用法

    import java.io.Serializable; import java.sql.Date; import java.sql.Timestamp; import javax.persisten ...

  10. Go 编译 && 工具

    编译和工具链 Go 的工具链非常丰富,从获取源码.编译.文档.测试.性能分析,到源码格式化.源码提示.重构工具等应有尽有 在 Go 中可以使用测试框架编写单元测试,使用统一的命令行即可测试及输出测试报 ...