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

对于每一个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. Android中使用LitePal操控SQLite数据库

    <第一行代码>读书手札 (一)什么是LitePal数据库 LitePal数据库是安卓的一个开源库,我们在以后的开发中,将会遇到许许多多的开源库,感谢开源社 区:因为开源社区的存在,一些我们 ...

  2. 【Docker】:全面认识Docker和基本指令

    Docker逐渐成为虚拟化技术的佼佼者,接下来会推出一系列的Docker相关技术文章,Docker技术也是架构师的必备技能. 什么是Docker Docker 是一个开源的应用容器引擎,基于Go语言, ...

  3. 织梦/dedecms采集怎么去除a标签

    dedecms采集去除a标签代码 DedeCMS采集规则-过滤-替换-技巧2009-01-14 15:491.采集去除链接[Copy to clipboard]CODE:{dede:trim}]*)& ...

  4. golang开发:环境篇(四)包管理器 glide的使用

    glide 是golang项目开发中是特别重要的软件,没有它,golang的项目可能都无法发布. 为什么要使用glide 平时我们开发Go项目的时候,使用第三方的包的时候都直接使用go get 去获取 ...

  5. Scratch编程:游泳的火柴人(四)

    “ 上节课的内容全部掌握了吗?反复练习了没有,编程最好的学习方法就是练习.练习.再练习.一定要记得多动手.多动脑筋哦~~” 01 — 游戏介绍 这是一款简单的小游戏,实现了一个手绘的火柴人在水里游泳. ...

  6. logback的使用和配置

    参考:https://www.cnblogs.com/warking/p/5710303.html https://www.cnblogs.com 一.logback简介 1.logback: Log ...

  7. List转换字典去重问题

    数据源 var list = new List<TestClass> { ,Name="}, ,Name="}, ,Name="}, ,Name=" ...

  8. OpenStack中虚拟机获取不到IP地址的解决方法

    OpenStack源码交流群: 538850354 系统环境: centos6.5 + icehouse多节点部署 问题描述: 使用测试镜像cirros,虚拟机实例可以正常启动,但是不能从IP池中获取 ...

  9. 【转载】Redis 4.0 自动内存碎片整理(Active Defrag)源码分析

    click原文链接原文链接:https://blog.csdn.net/zouhuajianclever/article/details/90669409阅读本文前建议先阅读此篇博客: Redis源码 ...

  10. Python_if语句

    1.if语句: color='红色' if color=='蓝色': print('我是蓝色') elif color=='红色': print('我是红色') else : print('未知') ...