一、实现原理

我们以前都是怎么判断素数的呢:

试除法: 若一个正整数N为合数,则存在一个能整除N的数k,其中\(2\leqslant k \leqslant \sqrt N\)。

具体实施如下:

inline int is_prime(int n){
if(n<2) return 0;
for(int i=2;i<=sqrt(n);i++){
if(n%i==0) return 0;
}
return 1;
}

这种方法的时间复杂度为\(O(\sqrt n)\)。

现在,我们希望更快地判断一个数是否为素数。

我们可以借助费马小定理来判断:

如果p是一个质数,而整数a不是p的倍数,则有

\[a^{p-1}\equiv 1\pmod p
\]

Miller-Robbin素数判定就是基于上述定理实现的,如果我们随机枚举一个\(a\),且\(a\)满足费马小定理,那么\(p\)就是素数。所以Miller-Robbin素数判定是一种随机性算法。

需要注意的是,我们这样判断素数的方法实际上利用的是费马小定理的逆定理。不幸的是,费马小定理的逆定理并不是一个真命题。

  • 存在\(a=2,p=341\)时满足费马小定理,而\(341=11*31\)却是合数

我们把像341这样的数称作伪素数。实际上,伪素数有无穷多组。

这意味着一次判断不足以保证我们的程序正确。当然,解决这个问题也十分简单。

我们只需要重复操作大约30次,便能将正确率提升到我们期待的水平。

另外,我们使用快速幂来计算\(a^{p-1}\)。总复杂度为\(O(logn)\)。

下面给出Miller-Robbin素数判定的模板:

int qpow(int a,int b,int mod){//快速幂
int res=1;
while(b){
if(b&1) res=(res%mod*a)%mod;
a=(a%mod)*a%mod;
b>>=1;
}
return res;
}
bool query_prime(int x){
if(x==2)return true;
if(x==1)return false;
for(int i=1;i<=30;i++){
int base=rand()%(x-1)+1;//随机枚举a
if(qpow(base,x-1,x)!=1) return false;//计算a^(p-1)%p的值
}
return true;
}

二、应用

判断一个正整数是否为素数

模板题:AT807 素数、コンテスト、素数

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int qpow(int a,int b,int mod){//快速幂
int res=1;
while(b){
if(b&1) res=(res%mod*a)%mod;
b>>=1;
a=(a%mod)*a%mod;
}
return res;
}
inline int miller_robbin(int num){//核心代码
for(int i=1;i<=30;i++){
int base=rand()%(num-1)+1;
if(qpow(base,num-1,num)!=1) return 0;
}
return 1;
}
signed main(){
int num;
scanf("%d",&num);
if(num==1){
printf("NO");
return 0;
}
miller_robbin(num)?printf("YES\n"):printf("NO\n");
return 0;
}

附赠一道水题:(主要是练习素数判定)

AT1476 素数判定

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll qpow(ll a,ll b,ll mod){
ll res=1;
while(b){
if(b&1)res=(res%mod*a)%mod;
a=(a%mod)*a%mod;
b>>=1;
}
return res;
}
bool query_prime(ll x)
{
if(x==2)return true;
if(x==1)return false;
for(int i=1;i<=30;i++){
ll base=rand()%(x-1)+1;
if(qpow(base,x-1,x)!=1)return false;
}
return true;
}
int main()
{
srand(time(NULL));
ll num;
scanf("%lld",&num);
if(query_prime(num)||(num%2!=0&&num%3!=0&&num%5!=0&&num!=1))printf("Prime\n");
else printf("Not Prime\n");
return 0;
}

三、小结

使用Miller-Robbin素数判定,我们可以将复杂度降低至\(O(logn)\)级别(常数阶可以被忽略)。这样比原来的方法会快很多。


[算法]Miller-Robbin素数判定的更多相关文章

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

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

  2. HDU2138 素数判定

    HDU2138 给定N个32位大于等于2的正整数 输出其中素数的个数 用Miller Rabin 素数判定法 效率很高 数学证明比较复杂,略过, 会使用这个接口即可. #include<iost ...

  3. Miller Rabin素数检测与Pollard Rho算法

    一些前置知识可以看一下我的联赛前数学知识 如何判断一个数是否为质数 方法一:试除法 扫描\(2\sim \sqrt{n}\)之间的所有整数,依次检查它们能否整除\(n\),若都不能整除,则\(n\)是 ...

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

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

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

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

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

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

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

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

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

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

  9. algorithm@ 大素数判定和大整数质因数分解

    #include<stdio.h> #include<string.h> #include<stdlib.h> #include<time.h> #in ...

随机推荐

  1. git常用命令学习配详细说明

    原文链接 把当前目录变成Git可以管理的仓库 git init 查看仓库当前的状态 git status 添加新/变动文件 git add <文件名> // 添加某个新文件(目录) git ...

  2. Error: java.net.ConnectException: Call From tuge1/192.168.40.100 to tuge2:8032 failed on connection exception

    先看解决方案,再看唠嗑,唠嗑可以忽略. 解决方案: 使用start yarn.sh启动yarn就可以了. 唠嗑: 今天学习Spark基于Yarn部署.然后总以为Yarn是让Spark启动的,提交程序的 ...

  3. wr720n v4 折腾笔记(四):安装inode客户端njitclient

    前记: 既然折腾到这里,那就不怕再折腾一下了,之前说过最终还是安装南浦月大神的固件,折腾了一圈,怎么不直接在官方界面上安装呢,这里给出直接安装的方法,就是修改固件头为wr720nv4. 0x01 修改 ...

  4. Bootstrap 基本配置与应用

    配置使用 下载文件引用 下载方式:Bootstrap官网 https://www.bootcss.com/ 引用 例: <head> <meta charset="utf- ...

  5. 【笔记3-31】Python语言基础-字典dict

    创建字典 dict1 = {'k1': 'v1', 'k2': 'v2', 'k3': 'v3', 'k4': 'v4'} dict2 = dict(k1='v1', k2='v2', k3='v3' ...

  6. PMP学习笔记(一)

    前9节列举出了很多例子来辅助理解什么是项目管理,在学习的过程当中听到了一些名词,查询过一些资料之后,在这里梳理出来 1.关键路径法 关键路径是指设计中从输入到输出经过的延时最长的逻辑路径.优化关键路径 ...

  7. ConcurrentHashMap(1.7版本和1.8版本)

     为什么要使用ConcurrentHashMap? ConcurrentHashMap是Java5中新增加的一个线程安全的Map集合,可以用来替代hashMap和HashTable.因为在并发编程中使 ...

  8. Python学习笔记:String类型所有方法汇总

    # 按字母表熟悉下string中的方法# A B C D E F G H I J K L M N O P Q R S T U V W X Y Z# 标红的为常用重点的方法!! str = " ...

  9. 基于.NetCore3.1搭建项目系列 —— 使用Swagger导出文档 (番外篇)

    前言 回顾之前的两篇Swagger做Api接口文档,我们大体上学会了如何在net core3.1的项目基础上,搭建一套自动生产API接口说明文档的框架. 本来在Swagger的基础上,前后端开发人员在 ...

  10. Python——图像手绘效果

    1.图像的RGB色彩模式 PIL PIL, Python Image Library PIL库是一个具有强大图像处理能力的第三方库 在命令行下的安装方法: pip install pillow fro ...