定义:##

Miller Rabin算法是一个随机化素数测试算法,作用是判断一个数是否是素数,且只要你脸不黑以及常数不要巨大一般来讲都比\(O(\sqrt n)\)的朴素做法更快。

定理:##

Miller Rabin主要基于费马小定理:

\[a ^ {p-1} \equiv 1 (mod p)$$其中$p$是质数。
于是就有~~闲得没事干的~~一群科学家们想,这个问题的逆命题是否成立呢?

> 逆命题:若对于任意$a$,$a ^ {p-1} \equiv 1 (mod p)$都成立,那么$p$是质数。

在很长一段时间里,所有人几乎都以为它是成立的。~~然鹅你们手玩一个$a=8, p = 9$试试~~
是的,这个东西被搞出了反例。不过幸运的是,用这个办法测试通过的数,还是有很大概率是质数的。
这好办,我们多搞几次不就可以当做它就是质数了吗!~~脸黑另说~~

##算法流程:##
首先我们还得了解一个叫二次探测定理的东西:

> $$若p是质数,且x^2 \equiv 1 (mod p), 则有x \equiv ±1 (mod p)\]

证明很简单,第一个式子右边丢过去平方差即可。由于p是质数,所以它肯定不是\((x-1)和(x+1)\)凑起来的,故两个里面总有一个是\(p\)的倍数。

而且很容易脑补的是,这个东西的逆命题是成立的。(划重点)

所以根据这两个定理,我们设计一波算法:

假设我们要判断的数是\(p\),那么\(2\)特判一波,剩下的质数肯定是奇数。

所以\(p-1\)一定是一个偶数。然后就好办啦!

我们把\(p-1\)分解成\(2^k * t\),当\(p\)是素数时,根据费马小定理有$$a ^ {2^k * t} \equiv 1 (mod p)$$

那么我们随机出一个\(a\),然后求出\(a^t\),再不断乘上\(a\),每次进行二次探测,边乘边模,若乘之前不符合二次探测,而乘之后符合,那么p是合数,不符合题意。自乘\(k\)次,最后得到\(a^{p-1}\),如果模\(p\)不等于1,则也是合数。(不符合费马小定理)

老祖宗告诉我们(这个我也不会证),每一次通过测试的数不是质数的概率为\(\frac{1}{4}\),则测试\(k\)次,错误的概率为\(\frac{1}{4^k}\),\(k>6\)的时候基本就血赚了。

代码:##

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int c[23] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43};
int n, m;
inline ll read() {
ll cnt = 0, f = 1; char c;
c = getchar();
while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + c - '0'; c = getchar();}
return cnt * f;
}
inline ll ksm(ll a, ll b, ll c) {
ll ans = 1;
while (b) {
if (b & 1) ans = ans * a % c;
a = a * a % c, b >>= 1;
}
return ans % c;
}
bool miller_rabin(int p) {
if (p == 1) return false;
if (p == 2) return true;
if (p % 2 == 0) return false;
bool f = 1;
for (register int i = 0; i <= 13; ++i) {
if (c[i] == p) return true;
ll x = p - 1, y = 0;
while (x % 2 == 0) x /= 2, ++ y; // 将p-1分解成2^y*x
ll cur = ksm(c[i], x, p); //计算出a^x % p
if (cur == 1) continue; //小优化,如果此时结果为1,那么无论如何自乘也为1
for (register int j = 1; j <= y; ++j) {
ll nxt = cur * cur % p; //不断自乘
if (nxt == 1 && cur != p - 1 && cur != 1) {
f = 0;
break;
}
cur = nxt;
}
if (cur != 1) f = 0;
if (!f) break;
}
return f;
}
int main() {
n = read(); m = read();
while (m--) {printf(miller_rabin(read()) ? "Yes\n" : "No\n");}
return 0;
}

Miller Rabin算法学习笔记的更多相关文章

  1. C / C++算法学习笔记(8)-SHELL排序

    原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...

  2. Miller Rabin算法详解

    何为Miller Rabin算法 首先看一下度娘的解释(如果你懒得读直接跳过就可以反正也没啥乱用:joy:) Miller-Rabin算法是目前主流的基于概率的素数测试算法,在构建密码安全体系中占有重 ...

  3. Manacher算法学习笔记 | LeetCode#5

    Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...

  4. Pollard rho算法+Miller Rabin算法 BZOJ 3668 Rabin-Miller算法

    BZOJ 3667: Rabin-Miller算法 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 1044  Solved: 322[Submit][ ...

  5. Miller Rabin 算法简介

    0.1 一些闲话 最近一次更新是在2019年11月12日.之前的文章有很多问题:当我把我的代码交到LOJ上,发现只有60多分.我调了一个晚上,尝试用{2, 3, 5, 7, 11, 13, 17, 1 ...

  6. Johnson算法学习笔记

    \(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...

  7. 某科学的PID算法学习笔记

    最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...

  8. 【数论基础】素数判定和Miller Rabin算法

    判断正整数p是否是素数 方法一 朴素的判定   

  9. Johnson 全源最短路径算法学习笔记

    Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...

随机推荐

  1. 贪心数列构造——cf1157D

    一开始将数列设置为0 1 2 3 4 5 6... 然后从左到右遍历,每位不够就增加即可 #include<bits/stdc++.h> using namespace std; #def ...

  2. vue双向绑定的原理

    什么是双向数据绑定?Vue是一个MVVM框架,数据绑定简单来说,就是当数据发生变化时,相应的视图会进行更新,当视图更新时,数据也会跟着变化. 实现数据绑定的方式大致有以下几种: - 1.发布者-订阅者 ...

  3. 如何有效管理Windows系统帐户权限

    权限是Windows管理的基础,当然与Windows用户关系最密切,平时接触最多的是与帐户相关的权限.对于Windows帐户权限的管理,你是否完全了解呢?下面,笔者以Winsows XP为例进行相关测 ...

  4. json的dump和dumps的区别

    dumps是将dict转化成str格式,loads是将str转化成dict格式. dump和load也是类似的功能,只是与文件操作结合起来了. In [1]: import json In [2]: ...

  5. SPSS数据编辑器界面 度量 名义 序号 标签

    SPSS数据编辑器界面 度量 名义 序号 标签 变量视图:变量视图用于管理变量的属性,包括变量名称,类型,标签,缺失值,度量标准等属性. 数据视图:数据视图用于管理录入的数据,一行表示一条记录在不同变 ...

  6. 移动端click点透bug

    移动端click点透bug click点透bug有一个特定的产生情况: 当上层元素是tap事件,且tap后消失,下层元素是click事件.这个时候,tap上层元素的时候就会触发下层元素的click事件 ...

  7. Vue .sync修饰符与$emit(update:xxx)写法问题

    在学习vue自定义事件的.sync修饰符实现改变数值时发现一个问题如下由于props的大小写命名:fatherNum,对应不同的$emit()会有不同的效果,具体如下: 使用.sync修饰符,即 // ...

  8. Python中好用的模块们

    目录 Python中好用的模块们 datetime模块 subprocess模块 matplotlib折线图 importlib模块 Python中好用的模块们 datetime模块 ​ 相信我们都使 ...

  9. Ubuntu环境下安装Scala以及安装IntelliJ Scala插件(Plugin)

    一.Scala介绍 1.结合Spark处理大数据 这是Scala的一个主要应用,而且Spark也是那Scala写的. 2.Java的脚本语言版  可以直接写Scala的脚本,也可以在.sh直接使用Sc ...

  10. linux普通用户无法登录mysql

    一.前言 本帖方法只适用于普通用户无法登录,但root用户可以登录的情况. 今天将war包放入linux后,运行报错,经过检查发现是数据库连接不上.奇怪的是,用户名和密码都是正确的,所以有了以下发现. ...