Pollard Rho算法浅谈
Pollard Rho介绍
Pollard Rho算法是Pollard[1]在1975年[2]发明的一种将大整数因数分解的算法
其中Pollard来源于发明者Pollard的姓,Rho则来自内部伪随机算法固有的循环
Pollard Rho算法在其他因数分解算法[3]中不算太出众,但其空间复杂度Θ(1)的优势和好打的代码使得OIer更倾向于使用Pollard Rho算法
毕竟试除法太慢了,谁没事打Pollard Rho不打试除法
Pollard Rho原理
生日悖论
如果一年只有365天(不计算闰年),且每个人的生日是任意一天的概率均相等,那么只要随机选取23人,就有50%以上的概率有两人同一天生日
解释:第一个人不会和前面的人重生日(因为前面没有人),第二个人不重生日的概率为364/365,第三个人363/365……以此类推,那么只要到第23个人,就有
,说明这时就有50%以上的概率有两人同生日
更多的,当一年有n天时,只要人数到达Θ(sqrt(n))的数量级,有至少两个人同一天生日的概率就可以达到50%以上
图象表达:
Miller Rabin素性测试[4][4']
其实Miller Rabin素性测试不是那么重要(因为不是Pollard Rho算法的核心),但没有它,Pollard Rho算法会被试除法拖慢到比朴素算法更差
这里就不再赘述,想要学习的请移步至维基百科(百度百科真是垃圾)
快速幂&比硬件还慢的快速乘&GCD
这应该是大多数数论算法的标配,不会的请先百度或谷歌
Floyd判圈算法[5]
Floyd判圈算法又叫龟兔赛跑算法,是用差速转移的方式快速判断是否进入环的算法
想象有一只兔子和一只乌龟按一个确定函数从同一个起点移动,兔子每次可以转移两次,乌龟可以转移一次
(OI算法中一张奇怪的图片)
那么如果这个确定函数上没有环,那么兔子一定会在乌龟前面,二者一定不会相交
否则,由于函数上有环,兔子一定会“追上”乌龟,也就是“套圈”
不仅如此,对算法分析可知,当兔子“追上”乌龟时,兔子也一定跑了刚好一圈(就是不证明,你来打我呀)
Pollard Rho算法的做法
介绍所有算法前先要声明一下:在每次操作前要先判断是不是素数,否则找不出原数的非平凡因子
这里要用Miller Rabin素性测试快速判断,以保证其高效性(不然提到这家伙是干什么的)
GCD优化+随机化试除法
试除法是一种朴素的因数分解算法,加了随机化后其实并没有多大用而且还更慢了
但是如果我们退而求其次——不直接寻找因子,而是寻找因子的倍数,然后用GCD找到因子本身呢
随机寻找到一个因子的倍数的概率为
,确实比直接找因子的随机化试除法好了一点点,但当因子很大时依旧没什么用
PS:在Pollard Rho算法中随机数算法一般用F(x)=x2+c(这个函数具有混沌性,实现又简单,而且调整参数c可以保证所有的数一定都能遇到,所以一般用这个算法,而不用其他算法)
向成熟的Pollard Rho算法迈进
把原来的一个随机数变成两个数的差,这样就得到了比较常见的Pollard Rho算法模板
看上去似乎并没有什么用(实际上对效率也没什么帮助),但是我们可以把两个随机数设为Floyd判圈算法中的“兔子”和“乌龟”,从而在走上“不归路”前及时退出
PS:看上去似乎到现在都还没有用到生日悖论的概率增大,但是实际上当寻找次数比较小时不记录的随机和记录的随机概率相近
减少GCD数目——过河拆桥优化法
每次产生一对随机数都要求一次GCD,对算法的效率有着很大影响。有什么办法可以减少求GCD的次数呢?
我们可以发现,把多个数相乘再取GCD一定不会使找出的因子大小更小
所以说,我们可以将K个差相乘,然后GCD一次判断,找到非平凡因子的概率就更大了
需要注意的是,当乘积变成要求分解的数的倍数时,说明最后一对随机数一定对结果有贡献,数对差一定是一个因子的倍数
不仅如此,当循环因为找到环而退出时应该把已有的乘积进行判断(连尸体都不放过)
PS:这里的K一般取127,我也不知道为什么
《算法导论》的优化——倍增求圈法
当随机数的转移算法比较复杂时,Floyd判圈算法的多次转移就会成为性能的瓶颈。有什么办法可以少转移呢?
可以想到,我们可以不直接寻找环的出现,而是在转移时标记一个记录点,当发现走到了记录点,就说明我们已经走了至少一圈环
但又要怎么打标记点呢?打得太少会退化,打得太多又会影响效率,必须要和环的长度差不多才行,这就变成了猜测环的长度的问题了
而每次猜测环的长度可以用倍增的方法,首先猜环的长度在K以内,如果没走到,那么不是猜小了就是记录点选错了,把记录点换成现在这个点,再继续猜测环的长度为2K
所以又怎么替代Floyd判圈算法呢?由于记录点自身也是随机数,具有一定的随机性,那就干脆直接代替Floyd判圈算法的“乌龟”得了
在已有算法上卡一卡常——让子弹再飞一会
- Miller Rabin素性测试的正确性很高,按洛谷P4718的题解中_皎月半洒花所说(现在原文章已改,无此段),在测试时只要测2和61就能过,但是要能100%过,需要从2到23的所有素数都试一遍[6]
- 用register运算符修饰临时变量,优化硬件速度(register可以让数据被存储到更快的CPU寄存器中)
- 用快一点的快速乘算法,并尽量减少强制类型转换的次数
P4718的代码——Pollard Rho算法
#define LL long long
bool IsPrime(LL);//返回素性测试结果
LL GCD(LL,LL);//返回两个数的GCD
LL Mix(LL,LL,LL);//返回两个数在模运算下的乘积 void MaxFactor(LL n,LL &ans){
if(n==||n<=ans||IsPrime(n)){
ans=max(ans,n);
return;//判断特殊情况:n为1或素数,n一定不能更新ans
}
for(LL c=rand()%(n-)+;;c++){
//为防止随机数无效化,使用死循环
LL t1=rand()%(n-)+,t2=(Mix(t1,t1,n)+c)%n;
LL p=,i=,g=;
while(t1!=t2){
p=Mix(p,abs(t1-t2),n);
if(!p){//乘积为0时说明找到了一个因子
g=GCD(n,abs(t1-t2));
if(g>&&g<n){
MaxFactor(g,ans);
MaxFactor(n/g,ans);
}
return;
}
++i;
if(i==){//当有127个数时强制测试
g=GCD(n,p);
if(g>&&g<n){
MaxFactor(g,ans);
MaxFactor(n/g,ans);
return;
}
p=,i=;
}
t1=(Mix(t1,t1,n)+c)%n;
t2=(Mix(t2,t2,n)+c)%n;
t2=(Mix(t2,t2,n)+c)%n;
}
g=GCD(n,p);
if(g>&&g<n){//循环退出后收尾
MaxFactor(g,ans);
MaxFactor(n/g,ans);
return;
}
}
}
参考资料
洛谷日报:https://www.luogu.org/blog/zenyz/pollardrho-kuai-su-fen-xie-zhi-yin-shuo
P4718题解:https://www.luogu.org/problemnew/solution/P4718
Pollard Rho算法——维基百科:https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
Miller Rabin素性测试——维基百科:https://zh.wikipedia.org/wiki/%E7%B1%B3%E5%8B%92-%E6%8B%89%E5%AE%BE%E6%A3%80%E9%AA%8C
——会某人
Pollard Rho算法浅谈的更多相关文章
- Pollard rho算法+Miller Rabin算法 BZOJ 3668 Rabin-Miller算法
BZOJ 3667: Rabin-Miller算法 Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 1044 Solved: 322[Submit][ ...
- 初学Pollard Rho算法
前言 \(Pollard\ Rho\)是一个著名的大数质因数分解算法,它的实现基于一个神奇的算法:\(MillerRabin\)素数测试(关于\(MillerRabin\),可以参考这篇博客:初学Mi ...
- Pollard Rho 算法简介
\(\text{update 2019.8.18}\) 由于本人将大部分精力花在了cnblogs上,而不是洛谷博客,评论区提出的一些问题直到今天才解决. 下面给出的Pollard Rho函数已给出散点 ...
- Kmp算法浅谈
Kmp算法浅谈 一.Kmp算法思想 在主串和模式串进行匹配时,利用next数组不改变主串的匹配指针而是改变模式串的匹配指针,减少大量的重复匹配时间.在Kmp算法中,next数组的构建是整个Kmp算法的 ...
- Miller Rabin素数检测与Pollard Rho算法
一些前置知识可以看一下我的联赛前数学知识 如何判断一个数是否为质数 方法一:试除法 扫描\(2\sim \sqrt{n}\)之间的所有整数,依次检查它们能否整除\(n\),若都不能整除,则\(n\)是 ...
- [算法]浅谈求n范围以内的质数(素数)
汗颜,数学符号表达今天才学会呀-_-# 下面是百度百科对质数的定义 质数(prime number)又称素数,有无限个. 质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数. 求质数的方法 ...
- 大整数分解质因数(Pollard rho算法)
#include <iostream> #include <cstring> #include <cstdlib> #include <stdio.h> ...
- Sunday算法浅谈
一.Sunday算法简介 Sunday算法在我看来比起Kmp和bm都更加容易理解,代码实现也更加简洁.Sunday算法由Daniel M.Sunday在1990年提出,它的思想跟BM算法很相似只不过S ...
- 算法浅谈之DP悬线法
悬线法 用途 解决给定矩阵中满足条件的最大子矩阵 做法 用一条线(横竖貌似都行)左右移动直到不满足约束条件或者到达边界 定义 \(left[i][j]\):代表从\((i,j)\)能到达的最左位置 \ ...
随机推荐
- [APIO 2010] [LOJ 3144] 奇怪装置 (数学)
[APIO 2010] [LOJ 3144] 奇怪装置 (数学) 题面 略 分析 考虑t1,t2时刻坐标相同的条件 \[\begin{cases} t_1+\lfloor \frac{t_1}{B} ...
- WPF绑定并转换
首先新建个项目,我的项目名叫BindConverterDemo,你的话什么都可以,我这里只是做demo 再建两个类,DataDemo,ConverterDemo 这个是DataDemo类 public ...
- 《Android程序设计》课程学习
一.课件内容 2019-2010-1学期课件,点击查看 二.作业相关 上交作业的方法 访问ftp://192.168.42.254:22,登录后找到自己的姓名文件夹,放入作业即可.登录账号为stu2, ...
- SICP 习题解 第二章
计算机程序的构造和解释习题解答 Structure and Interpretation os Computer Programs Exercises Answer 第二章 构造数据抽象 练习2.17 ...
- 解决 INSTALL FAILED CONFLICTING PROVIDER
1.现象: 2.产生原因 INSTALL FAILED CONFLICTING PROVIDER 产生的原因通常是因为系统中已经安装的apk的provider中的authorities相同了,导致在安 ...
- No qualifying bean of type xxx' available 的一种解决方法
获取bean Class beanClass = Class.forName(event.className); FilterEvent filterEvent = (FilterEvent)Bean ...
- 前端每日实战:86# 视频演示如何用纯 CSS 创作一个方块旋转动画
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/gjgyWm 可交互视频 此视频是可 ...
- jmeter性能工具 之监控cpu,内存等信息(四)
1.jmeter 本身不支持直接监控 cpu,内存等信息,需要去官网下载控件 JMeterPlugins-Standard-1.4.0.zip 解压好将其中\lib\ext\JMeterPlug ...
- 测试tensorflowgpu版本是否可用
输入一下代码即可 import tensorflow as tf print(tf.test.is_gpu_available())
- 预览下载的pdf的——pdf.js
1.需要到官网下载源码:https://mozilla.github.io/pdf.js/ 2. function(){ let url='./demo1.pdf'; window.location. ...