Miller Rabin算法学习笔记
定义:##
Miller Rabin算法是一个随机化素数测试算法,作用是判断一个数是否是素数,且只要你脸不黑以及常数不要巨大一般来讲都比\(O(\sqrt n)\)的朴素做法更快。
定理:##
Miller Rabin主要基于费马小定理:
于是就有~~闲得没事干的~~一群科学家们想,这个问题的逆命题是否成立呢?
> 逆命题:若对于任意$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算法学习笔记的更多相关文章
- C / C++算法学习笔记(8)-SHELL排序
原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...
- Miller Rabin算法详解
何为Miller Rabin算法 首先看一下度娘的解释(如果你懒得读直接跳过就可以反正也没啥乱用:joy:) Miller-Rabin算法是目前主流的基于概率的素数测试算法,在构建密码安全体系中占有重 ...
- Manacher算法学习笔记 | LeetCode#5
Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...
- Pollard rho算法+Miller Rabin算法 BZOJ 3668 Rabin-Miller算法
BZOJ 3667: Rabin-Miller算法 Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 1044 Solved: 322[Submit][ ...
- Miller Rabin 算法简介
0.1 一些闲话 最近一次更新是在2019年11月12日.之前的文章有很多问题:当我把我的代码交到LOJ上,发现只有60多分.我调了一个晚上,尝试用{2, 3, 5, 7, 11, 13, 17, 1 ...
- Johnson算法学习笔记
\(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...
- 某科学的PID算法学习笔记
最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...
- 【数论基础】素数判定和Miller Rabin算法
判断正整数p是否是素数 方法一 朴素的判定
- Johnson 全源最短路径算法学习笔记
Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...
随机推荐
- 贪心数列构造——cf1157D
一开始将数列设置为0 1 2 3 4 5 6... 然后从左到右遍历,每位不够就增加即可 #include<bits/stdc++.h> using namespace std; #def ...
- vue双向绑定的原理
什么是双向数据绑定?Vue是一个MVVM框架,数据绑定简单来说,就是当数据发生变化时,相应的视图会进行更新,当视图更新时,数据也会跟着变化. 实现数据绑定的方式大致有以下几种: - 1.发布者-订阅者 ...
- 如何有效管理Windows系统帐户权限
权限是Windows管理的基础,当然与Windows用户关系最密切,平时接触最多的是与帐户相关的权限.对于Windows帐户权限的管理,你是否完全了解呢?下面,笔者以Winsows XP为例进行相关测 ...
- json的dump和dumps的区别
dumps是将dict转化成str格式,loads是将str转化成dict格式. dump和load也是类似的功能,只是与文件操作结合起来了. In [1]: import json In [2]: ...
- SPSS数据编辑器界面 度量 名义 序号 标签
SPSS数据编辑器界面 度量 名义 序号 标签 变量视图:变量视图用于管理变量的属性,包括变量名称,类型,标签,缺失值,度量标准等属性. 数据视图:数据视图用于管理录入的数据,一行表示一条记录在不同变 ...
- 移动端click点透bug
移动端click点透bug click点透bug有一个特定的产生情况: 当上层元素是tap事件,且tap后消失,下层元素是click事件.这个时候,tap上层元素的时候就会触发下层元素的click事件 ...
- Vue .sync修饰符与$emit(update:xxx)写法问题
在学习vue自定义事件的.sync修饰符实现改变数值时发现一个问题如下由于props的大小写命名:fatherNum,对应不同的$emit()会有不同的效果,具体如下: 使用.sync修饰符,即 // ...
- Python中好用的模块们
目录 Python中好用的模块们 datetime模块 subprocess模块 matplotlib折线图 importlib模块 Python中好用的模块们 datetime模块 相信我们都使 ...
- Ubuntu环境下安装Scala以及安装IntelliJ Scala插件(Plugin)
一.Scala介绍 1.结合Spark处理大数据 这是Scala的一个主要应用,而且Spark也是那Scala写的. 2.Java的脚本语言版 可以直接写Scala的脚本,也可以在.sh直接使用Sc ...
- linux普通用户无法登录mysql
一.前言 本帖方法只适用于普通用户无法登录,但root用户可以登录的情况. 今天将war包放入linux后,运行报错,经过检查发现是数据库连接不上.奇怪的是,用户名和密码都是正确的,所以有了以下发现. ...