一、实现原理

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

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

具体实施如下:

  1. inline int is_prime(int n){
  2. if(n<2) return 0;
  3. for(int i=2;i<=sqrt(n);i++){
  4. if(n%i==0) return 0;
  5. }
  6. return 1;
  7. }

这种方法的时间复杂度为\(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素数判定的模板:

  1. int qpow(int a,int b,int mod){//快速幂
  2. int res=1;
  3. while(b){
  4. if(b&1) res=(res%mod*a)%mod;
  5. a=(a%mod)*a%mod;
  6. b>>=1;
  7. }
  8. return res;
  9. }
  10. bool query_prime(int x){
  11. if(x==2)return true;
  12. if(x==1)return false;
  13. for(int i=1;i<=30;i++){
  14. int base=rand()%(x-1)+1;//随机枚举a
  15. if(qpow(base,x-1,x)!=1) return false;//计算a^(p-1)%p的值
  16. }
  17. return true;
  18. }

二、应用

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

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

  1. #include<bits/stdc++.h>
  2. #define int long long
  3. using namespace std;
  4. inline int qpow(int a,int b,int mod){//快速幂
  5. int res=1;
  6. while(b){
  7. if(b&1) res=(res%mod*a)%mod;
  8. b>>=1;
  9. a=(a%mod)*a%mod;
  10. }
  11. return res;
  12. }
  13. inline int miller_robbin(int num){//核心代码
  14. for(int i=1;i<=30;i++){
  15. int base=rand()%(num-1)+1;
  16. if(qpow(base,num-1,num)!=1) return 0;
  17. }
  18. return 1;
  19. }
  20. signed main(){
  21. int num;
  22. scanf("%d",&num);
  23. if(num==1){
  24. printf("NO");
  25. return 0;
  26. }
  27. miller_robbin(num)?printf("YES\n"):printf("NO\n");
  28. return 0;
  29. }

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

AT1476 素数判定

  1. #include<bits/stdc++.h>
  2. #define ll long long
  3. using namespace std;
  4. ll qpow(ll a,ll b,ll mod){
  5. ll res=1;
  6. while(b){
  7. if(b&1)res=(res%mod*a)%mod;
  8. a=(a%mod)*a%mod;
  9. b>>=1;
  10. }
  11. return res;
  12. }
  13. bool query_prime(ll x)
  14. {
  15. if(x==2)return true;
  16. if(x==1)return false;
  17. for(int i=1;i<=30;i++){
  18. ll base=rand()%(x-1)+1;
  19. if(qpow(base,x-1,x)!=1)return false;
  20. }
  21. return true;
  22. }
  23. int main()
  24. {
  25. srand(time(NULL));
  26. ll num;
  27. scanf("%lld",&num);
  28. if(query_prime(num)||(num%2!=0&&num%3!=0&&num%5!=0&&num!=1))printf("Prime\n");
  29. else printf("Not Prime\n");
  30. return 0;
  31. }

三、小结

使用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. Swift:字符串(String)分割之Substring优雅转换

    认识Substring类型 这是一个全新的类型,看类名像是String的子类,但是大家千万别被误导了,Substring并不是String的子类,这是两个不同的类型,但是它们都继承了StringPro ...

  2. python浅学【网络服务中间件】之Redis

    一.关于NoSQL: NoSQL(NoSQL = Not Only SQL ),"不仅仅是SQL". 相比MySQL等关系型数据库,NoSQL为非关系型的数据存储 Nosql中比较 ...

  3. EFCore DbContext 报SqlException: Incorrect syntax near 'OFFSET'.

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSq ...

  4. Docker镜像拉取慢的解决方法

    镜像加速器配置: 下文配置引用于阿里云说明文档:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors 1. 安装/升级Docker客户 ...

  5. Python批量修改Excel中的文件内容

    import osimport xlrdfrom xlutils.copy import copydef base_dir(filename=None):    return os.path.join ...

  6. python逐行读取文本

    一.使用open打开文件后一定要记得调用文件对象的close()方法.比如可以用try/finally语句来确保最后能关闭文件. 二.需要导入import os 三.下面是逐行读取文件内容的三种方法: ...

  7. java并发安全

    本次内容主要线程的安全性.死锁相关知识点. 1.什么是线程安全性 1.1 线程安全定义  前面使用8个篇幅讲到了Java并发编程的知识,那么我们有没有想过什么是线程的安全性?在<Java并发编程 ...

  8. gold 波浪

  9. 学习笔记-EL

    仅作为学习过程中笔记作用,若有不正确的地方欢迎指正 目标 理解El的作用,熟练使用EL EL表达式与Jsp表达式对比来记 EL表达式的概念,作用,语法 Jsp作用主要是用来实现动态网页的,而动态网页中 ...

  10. 面向对象编程基础(java)

    面向对象编程基础 1.1 面向对象概述 在程序开发初期,大家使用的是结构化开发语言,也就是面向过程(opp),但随着市场需求剧增,软件的规模也越来越大,结构化语言的弊端也暴露出来. 开发周期无休止的拖 ...