Pollard Rho 质因数分解
暴力算法
这是一个暴力递归分解质因数的伪代码
void rp(int n) {if (n 是 质数) n 是 rp 的一个质因子, return;枚举找到 n 的一个非 1 因子 p;rp(p), rp (n / p);
}
其中判断质数可以用 Miller Rabin。该暴力复杂度的瓶颈是找因子,如果给定的 nnn 是一个大质数如 109+710^9+7109+7,那么枚举的复杂度就一飞冲天了。
生日悖论
假设 n=109+7n=10^9+7n=109+7,只有一个非 111 因子。
如果一个班上有 kkk 个人,那么有两个生日相同的人的概率是多少?
答案为 P(k)=1−∏i=1k365−i+1365P(k)= 1 - \prod_{i=1}^k \frac{365-i+1}{365}P(k)=1−∏i=1k365365−i+1。当 k=48k=48k=48 时,P(k)≈0.960598P(k) \approx 0.960598P(k)≈0.960598。
那么我们可以用生日悖论来进行找因子
我们在 [1,n][1,n][1,n] 中随便选一个数,那么他是因子的概率为 1n\frac{1}{n}n1。
我们在 [1,n][1,n][1,n] 中随便选两个数 aaa 和 bbb,那么 ∣a−b∣|a-b|∣a−b∣ 是因子的概率为 2n\frac{2}{n}n2。这相当于 a=b+na = b + na=b+n 和 a=b−na = b - na=b−n 两个情况。
我们在 [1,n][1,n][1,n] 中随便选 kkk 个数 a1∼aka_1 \sim a_ka1∼ak,对于任意两个数 aia_iai 和 aja_jaj,如果有 gcd(∣ai−aj∣,n)≠1\gcd(|a_i-a_j|,n) \not =1gcd(∣ai−aj∣,n)=1,意味着我们找到了 nnn 的一个因子,它的概率为 2×k(k−1)2n\frac{2 \times \frac{k(k-1)}{2}}{n}n2×2k(k−1)。当 k=nk = \sqrt{n}k=n 时,概率已经接近百分之百了。但如果求这 kkk 个数的两两差,复杂度又回到了 O(n)O(n)O(n),显然不可行。
伪随机函数
fi=(fi−12+c)modnf_i = (f_{i-1^2+c}) \bmod n fi=(fi−12+c)modn
其中 ccc 可以是 [1,n][1,n][1,n] 内的任意一个数,我们任取一个数作为 f1f_1f1,然后剩下的数列根据这个函数随机生成。可以发现在modp\bmod pmodp 下,一旦有两个数相同,那么这个数列会陷入循环节,陷入循环节前的长度期望是 n\sqrt nn 的。
那么这个函数的优点是什么呢?如果 gcd(fi−fj,n)≠1\gcd(f_i-f_j,n) \not=1gcd(fi−fj,n)=1,那么有 fi+1−fj+1=(fi−fj)(fi+fj)f_{i+1}-f_{j+1}=(f_i-f_j)(f_i+f_j)fi+1−fj+1=(fi−fj)(fi+fj),gcd(fi+1,fj+1,p)≠1\gcd(f_{i+1},f_{j+1},p) \not = 1gcd(fi+1,fj+1,p)=1。
算法实现
int f(int a, int n, int c)
{return (1ll * a * a + c) % n;
}
void factor(int n) {if (miller_rabin(n)) {z[++cnt] = n; return ;}int g = n;while (g == n) g = pollard_rho(n); //若 g == n,则这次 pollard_rho 的 rp 不好,没有找到因子factor(g), factorn(n / g);
}
现在我们要实现 Pollard_Rho 的主体了。Pollard_Rho 的思想就是在随机数列上选一些数与 nnn 求最大公约数,如果遇到环则跳出。现在有一个效率低下的双指针法。
int pollard_rho(int n) {int c = rand() % (n - 1) + 1;int v1 = c;int v2 = f(v1,n,c);while (v1 != v2) {int g = gcd(n, abs(v1 - v2));if (g > 1) return g;v1 = f(v1,n,c); //v1 跳一次v2 = f(v2,n,c); v2 = f(v2,n,c); //v2 跳两次}return n;
}
我们知道求 gcd\gcdgcd 的复杂度是 log\loglog 的,求太多次会使得代码时间复杂度低下。我们不如用倍增的思想,让 v2v2v2 在一个范围中跳上好几次,把这几次的结果一起求一下 gcd\gcdgcd。这样看上去比较玄学,但是对复杂度却如虎添翼。
int pollard_rho(int n) {int c = rand() % (n - 1) + 1;int v1 = 0;for (int s = 1, t = 2; s <<= 1, t <<= 1) {int v2 = v1, mul = 1;for (int i = s, step = 1; i < t; i++, step++) {v2 = f(v2, n, c);mul = 1ll * mul * abs(v1 - v2) % n;if (step == 128) {step = 0;int v = gcd(mul, n);if (v > 1) return v;}}int v = gcd(mul, n);if (v > 1) return v;v1 = v2;}
}
现在时间复杂度得到了大大提升,当然 Pollard_rho 还有许多更优的实现方式,甚至有许多比 Pollard_rho 快了不知道几十倍的质因数分解算法,但在算法竞赛中此法足矣。
Pollard Rho 质因数分解相关推荐
- 大整数分解——Pollard Rho算法
延续上一篇,这次来讲一讲大整数分解算法的应用. 要解决的问题很简单,对一个整数进行分解质因数. 首先还是效率非常低的暴力算法,相信大家都会,不多提. 和上次一样,当数达到非常大的时候,分解将变得非常困 ...
- 素数判定质因数分解(数论)(Miller Rabin)(Pollard Rho)
太玄学了! 我真的被概率的魅力折服了.此前我认为1便是1,0.9999999999-便是0.9999999999-. 但实际上它们有着千丝万缕的关系. 试想,如果一件事发生的概率是0.99999999 ...
- C++实现质因数分解
质数(prime number)又称素数,有无限个.一个大于1的自然数,除了1和它本身外,不能被其他自然数整除(除0以外)的数称之为素数(质数):否则称为合数.根据算术基本定理,每一个比1大的整数,要 ...
- c语言素数筛法与分解素因数,质因数分解及代码:
计算方法 短除法 求一个数分解质因数,要从最小的质数除起,一直除到结果为质数为止.分解质因数的算式的叫短除法,和除法的性质差不多,还可以用来求多个个数的公因式: 求最大公因数的一种方法,也可用来求最小 ...
- 质因数分解及算法实现
每个合数都可以写成几个质数相乘的形式,这几个质数就都叫做这个合数的质因数.如果一个质数是某个数的因数,那么就说这个质数是这个数的质因数.而这个因数一定是一个质数. 定义 质因数(或质因子)在数论里是指 ...
- Python 大数的质因数分解
肝了一天总算把大数质因数分解搞定了,这篇文章主要涉及了 Pollard rho 算法和试除法 我用了若干个质数的平方来对比这两个算法的性能,发现: 7e5 以上的数用 Pollard rho 算法更快 ...
- 64位以内Rabin-Miller 强伪素数测试和Pollard rho 因数分解解析
在求解POJ1811题Prime Test中应用到的两个重要算法是Rabin-Miller强伪素数测试和Pollard r因数分解算法.前者可以在的时间内以很高的成功概率判断一个整数是否是素数.后者可 ...
- 整数的素因子分解:Pollard rho method
参考: 1.CLRS<算法导论> 2.http://www.csh.rit.edu/~pat/math/quickies/rho/#algorithm Pollard rho方法是随机算法 ...
- Poj 1811 Prime Test 素数测试 Miller-Rabin 与 整数的因子分解 Pollard rho
随机化算法,想尝试自己写一下,最后还是变成了抄代码... 代码参考了:POJ 1811 Prime Test(大素数判断和素因子分解) - kuangbin - 博客园 学习链接: Miller-Ra ...
- 素数、最大公约数、最下公倍数、质因数分解
2013-08-18 11:20:43 素数.最大公约数.最下公倍数.质因数分解都是与素数相关的,解决了素数的问题,其他的都可以此为基础求解. 小结: 求1到n之间的素数的基本方法是通过遍历2到sqr ...
最新文章
- jetty9请求form表单太小限制
- Linux——33条小技巧
- PostgreSQL 10.1 手册_部分 II. SQL 语言_第 12 章 全文搜索_12.9. GIN 和 GiST 索引类型
- GitHub使用教程for Eclipse
- centos 5.5中如何由一般用户切换为root用户
- 天气预报HTML代码
- 如何向开源软件贡献自己的力量
- Bootstrap布局
- pytorch torch.nn.MSELoss
- mysql 是如何利用索引的_10 分钟搞明白 MySQL 是如何利用索引的!
- C++之父谈C++:一天之内你就能学会出色使用C++
- 去除本机利用ssh协议登陆远程机器的痕迹
- 【转】Data truncation: Truncated incorrect DOUBLE value:Mysql Update时
- 02WCF初识:ServiceEndpoint
- 精通Javascript+jQuery视频下载地址
- 防止SQL注入的五种方法
- 正则表达式的进阶用法——预查与分组
- 如何设置文件的默认打开方式
- 抠图:基于单个原色通道
- 数据传输/文件传输:两台电脑怎么传文件?
热门文章
- Todd Lammle's CCNA IOS Commands Survival Guide
- chrome 设置保护眼睛颜色
- 织梦个人网站即时到账支付插件
- 怎么用c语言让电脑定时开关机,电脑定时开关机,教您怎么设置电脑定时开关机...
- oracle中的than,range分区values less than,代表的是小于等于还是小于啊。
- hibernate_Hibernate记录:常见问题的提示和解决方案
- 科学研究设计六:有效性威胁
- 程序员怎样更优雅的接私活赚外快
- java 如何清除临时文件_如何删除Java中的临时文件?
- 《Qt on Android核心编程》介绍