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

对于每一个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. 剑指offer66:机器人的运动范围

    1 题目描述 地上有一个m行和n列的方格.一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子. 例如,当k为18时,机器 ...

  2. C++ 中三种继承方式的理解

    一.公有继承(public inheritance) 1.概念:当类的继承方式为公有继承时,基类的公有成员和保护成员的访问属性在派生类中不变,而基类的私有成员不可以直接访问. 实验一下:   我们用代 ...

  3. 剪贴板神器:Ditto

    ditto – 善用佳软 免费开源的 Windows 管理剪贴板,让你处理文字更高效:Ditto - 少数派

  4. 【C#】课堂知识点#3

    1.讲解了实验1中,利用Char.is***来进行判断字符类型. using System; using System.Collections.Generic; using System.Linq; ...

  5. Linux安装JDK,Tomcat,Mysql+部署项目

    安装VMWare虚拟机 下载地址(http://www.onlinedown.net/soft/2062.htm) 安装步骤很简单(除了选择安装路径),傻瓜式安装 同意协议 选择安装路径 安装 完成 ...

  6. netty--使用注意事项

  7. redis有序集合数据类型---sortedset

    一.概述 redis有序集合和集合一样,也是string类型元素的集合,且不允许重复的成员. 不同的是每个元素都会关联一个double类型的分数. redis正式通过分数来为集合中的重圆进行从小到大的 ...

  8. sublime text3 关闭更新提醒

    Preferences->settings 在Preferences.sublime-setting --User中 增加: "update_check":false,

  9. pip源设置为国内源

    windows系统步骤如下: (1)打开文件资源管理器(文件夹地址栏中) (2)地址栏上面输入 %appdata% (3)在这里面新建一个文件夹 pip (4)在pip文件夹里面新建一个文件叫做 pi ...

  10. jquery中checkbox的全选与反选

    <!DOCTYPE html><html><head> <meta charset="utf-8" /> <title> ...