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 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...
随机推荐
- tyvj 1194 划分大理石(多重背包)
传送门 解题思路 二进制优化多重背包裸题. 代码 #include<iostream> #include<cstdio> #include<cstring> #in ...
- 应用程序正常初始化(0xc0150002)失败的终极解决方案
转自VC错误:http://www.vcerror.com/?p=62 最近做一个项目写了一个VC6下的MFC程序,结果传到别人的机子上(WIN7)出现了应用程序正常初始化(0xc0150002)失败 ...
- 一些关于Hibernate延迟加载的误区
最近面试别人,正好出的笔试题中有道关于Hibernate延迟加载的问题,聊天过程中发现很多人对Hibernate的延迟加载有些理解误区,写 些东东在这里,希望对大家有所帮助. 首先是第一个误区:延迟加 ...
- Quartz 定时任务配置(spring中)
<!-- Quartz --> <bean name="task" class="com.geostar.geosmarter.nodemanag ...
- 18.scrapy_maitian
ershoufang.py # -*- coding: utf-8 -*- import scrapy class ErshoufangSpider(scrapy.Spider): name = 'e ...
- 腾讯bugly接入插件(CocosCreator)
下载: plugin-bugly.zip (1.4 MB) 插件开源地址: https://github.com/tidys/CocosCreatorPlugins/tree/master/packa ...
- iOS逆向系列-Reveal
概述 Reveal是一款调试iOS程序UI界面的神器. 官网地址:https://revealall.com 下载:https://revealapp.com/download/ 建议下载Reveal ...
- sql 根据列名查所属表名
比如 有一个jueseID字段,想知道这个字段是哪个表里的. 第一步: select * from syscolumns where name = 'jueseID' 第二步: select * fr ...
- 【分块】P4135 作诗
分块太暴力惹... 没做出来.看了题解qaq 分析: 两头$\sqrt{n}$暴力维护 预处理ans[i][j],sum[i][j] sum[i][j]是一个前缀和,前i块值为j的数量 ans[i][ ...
- Ubuntu vi命令
最近在使用ubuntu,在linux下,要编辑文件或者其他的文本文件,哪那么一个ubuntu linux下的强大的文本编辑工具就不得不提了,那就是VI编辑器.下面把VI常用到的命令行贴出来. :w ...