Miller-Rabin 素性测试

Miller-Rabin 素数测试

一本通上的M-R不透彻啊~

Miller-Rabin是利用随机化算法判断一个数是合数还是素数。

首先,如果一个数N是素数,那么他一定满足费马小定理。

\(a^{N-1}\equiv1\pmod N\)

我们可以任取数字a,计算这个式子的值来判断N是否为素数。

但是这么做不靠谱啊,有很多合数会被卡~

我们介绍一个相关的引理。

当p是素数且p大于2时,\(1\bmod p\)的平方根只有1和-1。

证明:

假设x是\(1\bmod p\)的平方根,则有\(x^2\equiv1\pmod p\)

则有\((x+1)(x-1)\equiv 0\pmod p\)

也就是说\((x+1)(x-1)\)能够整除素数p。根据欧几里得引理,(x+1)或(x-1)整除p,也就是\(x\equiv1\pmod p\)和\(x\equiv-1\pmod p\)

我们假设n是一个素数(n>2),则n-1是一个偶数,且能被表示成\(2^s*d\)的形式,d是奇数。

那么对于任意的a和\(0\le r\le s-1\),有\(a^d\equiv1\pmod n\)和\(a^{2^rd}\equiv -1\pmod n\)。

为什么呢?因为费马小定理。对于一个素数n,有\(a^{n-1}\equiv1\pmod n\),由于上面的引理,如果我们不断对\(a^{n-1}\)取平方根,我们总会得到1或-1。如果我们得到了-1,则\(a^{2^rd}\equiv -1\pmod n\)成立,判定p是素数。如果我们从未得到-1,通过这个过程我们取遍了2的所有幂次,则\(a^d\equiv1\pmod n\)成立。

Miller-Rabin素性测试就在于上述原理的逆否,如果我们找到了一个a,使得对于任意的\(0\le r\le s-1\),满足以下两个式子:\(a^d\not\equiv1\pmod n\),\(a^{2^rd}\not\equiv-1\pmod n\),n就不是一个素数。

如果一个数a通过了上述测试,就称a是n是合数的凭证。否则称a是n是素数的强伪证,也就是他可能出锅。(毕竟是随机化算法嘛)我们就需要多找几个a,使得被误判的概率更小。

Pollard's Rho算法

给出一个数N,快速提取N的[一个]因数。

生日悖论

在一群学生中,随机选一个学生,则他的生日为4 月 1 号的概率为\(\frac 1 {365}\)。

转化为古典概型,在[1,365]中随机选取一个数,该数为90的概率为\(\frac 1 {365}\)

然后我们现在需要随机选取2个人,他们两个人生日相同的概率也是\(\frac 1{365}\)

然而我们现在随机选取3个人,他们中任意两个人生日相同的概率是:

我们利用单步容斥,任意两人生日相同的概率=1-没有两人生日相同的概率。

没有两人生日相同的概率为\(\frac{365*364*363}{365*365*365}\),约为0.9917958341152186(使用Windows7的计算器算出),则任意两人的生日相同概率为0.0082041658847814(同上)。

我们现在随机选取k个人,则容易得到的是,任意两个人生日相同的概率为:

\(1-\frac{365!}{(365-k)!*365^k}\)(k<=365)。

当k>365,P=1

当k=23时,P>50%,大概是\(\sqrt N\)

当k=42时,P>90%

当k=100是,P=99.99996928%

这个很大了~

因数分解

我们选取k个数,询问是否存在\(x_i-x_j\)能够整除N

当\(k=\sqrt N\),可能性提高到了50%

我们将可能性从\(\frac 1 N\)提高到\(\sqrt{\frac1 N}\)。

对于一个\(10^{10}\)的大整数,我们只需要做\(10^5\)次比较,除法。这还是炸了。。。

我们选取k个数,询问是否存在\(gcd(x_i-x_y,N)>1\)。看着是棒了好多了,

下面我们介绍P-R

Pollard's Rho算法

这个Pollard's Rho算法只将两个数放在内存中。我们不一下子随机生成k个数,反而一个一个生成检查相邻的2个数。反复执行这个步骤。

我们有一个Interesting的函数\(f(x)=(x^2+a)\mod N\)。这个a可以自己指定,也可以rand(),这个不是重点。

我们从\(x_1=2\)开始,让\(x_2=f(x_1)\)....\(x_{i+1}=f(x_i)\)。如果相邻的两个数的差与N的gcd大于1,返回他们的gcd。作为N的因子。但是这个可能会出现环(详见模域平方)。

有一个Floyed发明的神奇的算法。小明和小红在操场上跑圈,小明的速度恰好是小红的2倍,最后小明跑2圈时,小红恰好跑了1圈,小明从小红的后面追上小红,但是实际上小明比小红快整整一圈。

我们用floyed判环,我们如果失败了我们只需要重新选择一个a即可。

这就是P R算法。

upd 9.6

然后洛谷板子题真心坑人各种卡常,瞬间变身卡同学

然后这是代码(抄了最优解Rank1好多。。。)

外加Miller-Rabin素数测试,有空更新一下

(这份代码细节不太透彻,留个坑,NOIP后重新透彻一遍)

#include <bits/stdc++.h>

using namespace std;

long long const_A = 5;

unsigned long long myrand()
{
static unsigned long long seed = 3589425289U;
return seed * 74658973 + 348633;
} void read(long long &x)
{
x = 0;
static char ch;
ch = getchar();
while (!isdigit(ch))
ch = getchar();
while (isdigit(ch))
{
x = x * 10 + ch - 48;
ch = getchar();
}
} inline long long qpow(long long x, long long y, long long p)
{
long long ans = 1;
while (y > 0)
{
if (y & 1)
ans = ((__int128)ans * (__int128) x) % p;
x = ((__int128)x * (__int128)x) % p;
y >>= 1;
}
return ans;
} bool Miller_Rabin(long long N, long long a)
{
if (N == a)
return true;
if (N == 46856248255981LL || N < 2 || N % a == 0)
return false;
long long d = N - 1;
while (!(d & 1))
d >>= 1;
long long t = qpow(a, d, N);
while (d != N - 1 && t != 1 && t != N - 1)
{
t = ((__int128)t * (__int128)t) % N;
d <<= 1;
}
return (t == N - 1) || ((d & 1) == 1);
} inline bool prime(long long x)
{
return (Miller_Rabin(x, 2) && Miller_Rabin(x, 3) && Miller_Rabin(x, 7) && Miller_Rabin(x, 61) && Miller_Rabin(x, 24251));
} inline long long gcd(long long a, long long b)
{
if (!a) return b;
if (!b) return a;
int t = __builtin_ctzll(a | b);
a >>= __builtin_ctzll(a);
do
{
b >>= __builtin_ctzll(b);
if (a > b)
{
long long tt = a;
a = b;
b = tt;
}
b -= a;
}
while(b != 0);
return a << t;
} long long Pollards_Rho(long long n)
{
if (n % 2 == 0)
return 2;
if (n % 3 == 0)
return 3;
long long x = 0, y = x, t = 1, q = 1, c = (rand() % (n - 1)) + 1;
for (register int k = 2; ; k <<= 1, y = x, q = 1)
{
for (register int i = 1; i <= k; ++i)
{
x = (((__int128)x * (__int128)x) % n + c) % n;
q = ((__int128)q * (__int128)abs(x - y)) % n;
if ((i & 127) == 0)
{
t = gcd(q, n);
if (t > 1)
break;
}
}
if (t > 1 || (t = gcd(q, n)) > 1)
break;
}
return t;
} void find(long long x, long long &ans)
{
// printf("find %lld %lld\n", x, ans);
if (x <= ans || x == 1)
return;
if (prime(x))
{
ans = ans > x ? ans : x;
return;
}
long long t = x;
while (t == x)
t = Pollards_Rho(x);
while (x % t == 0)
x /= t;
find(t, ans);
find(x, ans);
} int main()
{//freopen("d.txt", "r", stdin);
// freopen("w.txt", "w", stdout);
long long T;
read(T);
while (T--)
{
long long x;
read(x);
long long ans = 0;
find(x, ans);
if (x == ans)
printf("Prime\n");
else
printf("%lld\n", ans);
}
return 0;
}

Miller-Rabin素性测试|Pollard's Rho算法的更多相关文章

  1. POJ1811_Prime Test【Miller Rabin素数测试】【Pollar Rho整数分解】

    Prime Test Time Limit: 6000MS Memory Limit: 65536K Total Submissions: 29193 Accepted: 7392 Case Time ...

  2. HDU1164_Eddy&#39;s research I【Miller Rabin素数测试】【Pollar Rho整数分解】

    Eddy's research I Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  3. HDU 3864 D_num Miller Rabin 质数推断+Pollard Rho大整数分解

    链接:http://acm.hdu.edu.cn/showproblem.php? pid=3864 题意:给出一个数N(1<=N<10^18).假设N仅仅有四个约数.就输出除1外的三个约 ...

  4. 【快速因数分解】Pollard's Rho 算法

    Pollard-Rho 是一个很神奇的算法,用于在 $O(n^{\frac{1}4}) $的期望时间复杂度内计算合数 n 的某个非平凡因子(除了1和它本身以外能整除它的数).事书上给出的复杂度是 \( ...

  5. Pollard's Rho算法简单总结

    先贴一份代码在这. 最近几天实在是太忙了没时间更新了. 代码 #include <iostream> #include <cstdio> #include <cstdli ...

  6. Pollard Rho算法浅谈

    Pollard Rho介绍 Pollard Rho算法是Pollard[1]在1975年[2]发明的一种将大整数因数分解的算法 其中Pollard来源于发明者Pollard的姓,Rho则来自内部伪随机 ...

  7. 数学基础IV 欧拉函数 Miller Rabin Pollard's rho 欧拉定理 行列式

    找了一些曾经没提到的算法.这应该是数学基础系最后一篇. 曾经的文章: 数学基础I 莫比乌斯反演I 莫比乌斯反演II 数学基础II 生成函数 数学基础III 博弈论 容斥原理(hidden) 线性基(h ...

  8. 关于素数:求不超过n的素数,素数的判定(Miller Rabin 测试)

    关于素数的基本介绍请参考百度百科here和维基百科here的介绍 首先介绍几条关于素数的基本定理: 定理1:如果n不是素数,则n至少有一个( 1, sqrt(n) ]范围内的的因子 定理2:如果n不是 ...

  9. Pollard's rho algorithm和涉及到的两个循环检测算法

    0. 简单介绍 Pollard的\(\rho\)算法是John Pollard在1975年发明的,用于分解质因数[1].假定被分解的数为N,N的最小的质因数为\(p(p\ne N)\),那么该算法可以 ...

随机推荐

  1. gradle_学习_00_资源贴

    一.官方资料 1.Gradle User Guide 中文版 二.精选资料 1.Gradle学习系列之一——Gradle快速入门 2.Gradle教程

  2. Hibernate - POJO 类和数据库的映射文件*.hbm.xml

    POJO 类和关系数据库之间的映射可以用一个XML文档来定义. 通过 POJO 类的数据库映射文件,Hibernate可以理解持久化类和数据表之间的对应关系,也可以理解持久化类属性与数据库表列之间的对 ...

  3. BLOB (binary large object)

    BLOB (binary large object),二进制大对象,是一个可以存储二进制文件的容器. 在计算机中,BLOB常常是数据库中用来存储二进制文件的字段类型. BLOB是一个大文件,典型的BL ...

  4. 趣味Shell

    Richard M. Stallman大神是谁就不用说了,一时来了兴趣,想看看Linux系统下有多少程序有这位大神参与编写的. 先把所有命令导出到文件中,遍历所有命令,用man手册查一下并过滤Stal ...

  5. Mybatis学习--动态SQL

    学习笔记,选自Mybatis官方中文文档:http://www.mybatis.org/mybatis-3/zh/dynamic-sql.html MyBatis 的强大特性之一便是它的动态 SQL. ...

  6. ACM学习历程—HDU5476 Explore Track of Point(平面几何)(2015上海网赛09题)

    Problem Description In Geometry, the problem of track is very interesting. Because in some cases, th ...

  7. ACM学习历程—HDU 5025 Saving Tang Monk(广州赛区网赛)(bfs)

    Problem Description <Journey to the West>(also <Monkey>) is one of the Four Great Classi ...

  8. Lisp的本质(The Nature of Lisp)

    Lisp的本质(The Nature of Lisp) 作者 Slava Akhmechet                             译者 Alec Jang 出处: http://w ...

  9. Parallel Programming-多消费者,多生产者同时运行并行

    在上一篇文章演示了并行的流水线操作(生产者和消费者并行同时执行),C#是通过BlockingCollection这个线程安全的对象作为Buffer,并且结合Task来实现的.但是上一篇文章有个缺陷,在 ...

  10. POJ1995:Raising Modulo Numbers

    二进制前置技能:https://www.cnblogs.com/AKMer/p/9698694.html 题目传送门:http://poj.org/problem?id=1995 题目就是求\(\su ...