定义:##

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. C++如何判断某一文件是否存在

    函数名: access 功 能: 确定文件的访问权限 用 法: int access(const char *filename, int amode); 程序例: #include <stdio ...

  2. golang中使用gorm连接mysql操作

    一.代码 package main import ( "fmt" "github.com/jinzhu/gorm" _ "github.com/go- ...

  3. POJ 2954 /// 皮克定理+叉积求三角形面积

    题目大意: 给定三角形的三点坐标 判断在其内部包含多少个整点 题解及讲解 皮克定理 多边形面积s = 其内部整点in + 其边上整点li / 2 - 1 那么求内部整点就是 in = s + 1 - ...

  4. printk函数

    一个不同是 printk 允许你根据消息的严重程度对其分类, 通过附加不同的记录级别或者 优先级在消息上. 你常常用一个宏定义来指示记录级别. 例如, KERN_INFO, 我们之前曾 在一些打印语句 ...

  5. spring:AOP面向切面编程(注解)03

    使用注解写aop时最好使用环绕通知写 切面类: /** * 用于记录日志的工具类,它里面提供了公共的代码 */ @Component("logger") @Aspect //表示当 ...

  6. Pascal代码自动格式化

    const WEnter=; key=; next_line:..WEnter]of string=(';','begin','else','then','repeat','do','var'); k ...

  7. Qt下QMainWindow内部QTableView不能自适应大小

    中央窗体设置的是一个QWidget 一直排查不到原因 最后发现为 因为布局中为QTableView设置了对齐方式 取消即可!

  8. android 往sd卡中写入文件

    在调用前需要判断是否有写入权限 Environment类提供了比较丰富的方法 static File getDataDirectory() 获得android data的目录. static File ...

  9. 常用DOM API总结

    一. 获取节点 1. 获取元素节点 getElementsById getElementsByTagName getElementsByClassName 2. 获取属性节点 getAttribute ...

  10. 「题解」NOIP模拟测试题解乱写I(29-31)

    NOIP模拟29(B) T1爬山 简单题,赛时找到了$O(1)$查询的规律于是切了. 从倍增LCA那里借鉴了一点东西:先将a.b抬到同一高度,然后再一起往上爬.所用的步数$×2$就是了. 抬升到同一高 ...