Pollard Rho算法分解因数
分解因数算法
文章目录
- 分解因数算法
- 朴素算法
- 唯一分解定理优化
- Pollard Rho算法
- 0.生日悖论
- 1.如何产生随机数
- 2.如何检查已经陷入了循环?
- 3.最大公因数优化
- 完整代码
- BUUCTF-Alice和Bob
给定一个正整数N,求其所有质因数
朴素算法
最贴近人的想法,就是从2开始一直到N\sqrt{N}N,用N取除以这些数,只要是能够整除就是因数,然后判定该因数是否是素因数
for(int i=2;i<=sqrt(N);i++){if(N%i==0){if(isPrime(i)){//i是N的素因数}}
}
唯一分解定理优化
任何正整数N都可以分解为若干个素数的乘积
N=p1k1p2k2...pnknN=p_1^{k_1}p_2^{k_2}...p_n^{k_n} N=p1k1p2k2...pnkn
比如48=24×3148=2^4\times 3^148=24×31
对于刚才纯朴素的做法,我们在找到222是48的素因数之后,如果不加处理后来又会发现4是48的因数但不是素因数,
可以将2k2^k2k从N的所有因数中去掉
int temp=N;
for(int i=2;i<=sqrt(temp);++i){if(temp%i==0){//i是temp的素因数,之所以没有判断素性就直接说是素因数,是因为有下面这个while保证while(temp%i==0){//实际上相当于筛子,筛去了i^k因子temp/=i;//由于temp%i=0因此i整除temp,此举将temp中所有i因数即其幂去掉}}
}
if(temp!=1){//最后剩下的temp也是N的素因数
}
只判断temptemp%i==0temp貌似只能说明iii是temptemptemp的因数,为什么还能将得到更严格结论"iii是temptemptemp的素因数"呢?
假设iii是temptemptemp的合因数
根据唯一分解定理,i=p1p2...pn,pi为素数i=p_1p_2...p_n,p_i为素数i=p1p2...pn,pi为素数
显然对于一个合数,i至少有两个素因数,不妨设为1<p1,p2<i1<p_1,p_2<i1<p1,p2<i
则p1∣i,i∣temp⇒p1∣tempp_1|i,i|temp\Rightarrow p_1|tempp1∣i,i∣temp⇒p1∣temp
那么p1p_1p1是temptemptemp的比i小的素因数
现在将时光回溯到i=p1i=p_1i=p1时,我们的while循环做了一件事:
while(temp%p1==0){temp/=p1;}
此举保证了出while循环的时候,temp不再含有p1p1p1因子,也就是p1∤tempp1 \nmid tempp1∤temp
现在时光前进到i=tempi=tempi=temp时,我们刚刚得到结论p1∣tempp_1| tempp1∣temp
于是产生了矛盾
因此假设不成立,即iii是temptemptemp的素因数
Pollard Rho算法
ρ\rho ρ
算法思想
朴素算法是从[2,N][2,\sqrt{N}][2,N]里面遍历所有数找N的因数
而现在我们不轮着找,而是挑着找,就类似于抽样检测.
用随便挑的两个数的差去找,啥意思呢?
∀x1,x2∈[2,N]\forall x_1,x_2\in [2,\sqrt{N}]∀x1,x2∈[2,N],我们求∣x2−x1∣|x_2-x_1|∣x2−x1∣,然后用这个数去试是否是NNN的因数
为啥不直接选一个∀x∈[2,N]\forall x\in[2,\sqrt{N}]∀x∈[2,N],然后用这个x去比划N,而是选两个x的差去比划呢?
0.生日悖论
这个只能用概率解释了,生日悖论问题
1.考虑从[1,1000][1,1000][1,1000]上选k个数,求任意两个数的差不等于x的概率
2.考虑一伙子k个人,任意两个人生日不同的概率(生日悖论)
上面那个我不会求,下面这个我会
假设一年有n天,求k个人生日都不相同的概率
第一个人的生日可以在n天中的任意一天,有n种情况
第二个人的生日不能和第一个人相同,有n-1种情况
第三个人的生日不能和前两个人相同,有n-2种情况
…
第k个人的生日不能和前k-1个人相同,有n-(k-1)种情况
因此k个人生日都不相同的概率为
P=n(n−1)(n−2)...(n−(k−1))nk=nn×n−1n×n−2n×...×n−k+1n=1×(1−1n)×(1−2n)×...×(1−k−1n)P=\frac{n(n-1)(n-2)...(n-(k-1))}{n^k}\\ =\frac{n}{n}\times \frac{n-1}{n}\times \frac{n-2}{n}\times ...\times \frac{n-k+1}{n}\\ =1\times (1-\frac{1}{n})\times (1-\frac{2}{n})\times ...\times (1-\frac{k-1}{n}) P=nkn(n−1)(n−2)...(n−(k−1))=nn×nn−1×nn−2×...×nn−k+1=1×(1−n1)×(1−n2)×...×(1−nk−1)
这个数可不好求,但是可以放缩,用到的是高中就见过的老伙计了ex≥x+1e^x\ge x+1ex≥x+1
1−in≤e−in1-\frac{i}{n}\le e^{-\frac{i}{n}} 1−ni≤e−ni
因此
P=1×(1−1n)×(1−2n)×...×(1−k−1n)≤e−1n×e−2n×...×e−k−1n=e−1n∑i=1k−1i=e−k(k−1)2nP=1\times (1-\frac{1}{n})\times (1-\frac{2}{n})\times ...\times (1-\frac{k-1}{n})\\ \le e^{-\frac{1}{n}}\times e^{-\frac{2}{n}}\times ...\times e^{-\frac{k-1}{n}}\\ =e^{-\frac{1}{n}\sum_{i=1}^{k-1} i}\\ =e^{-\frac{k(k-1)}{2n}} P=1×(1−n1)×(1−n2)×...×(1−nk−1)≤e−n1×e−n2×...×e−nk−1=e−n1∑i=1k−1i=e−2nk(k−1)
即k个人生日都不同的概率小于等于e−k(k−1)2ne^{-\frac{k(k-1)}{2n}}e−2nk(k−1)那么存在两个人生日相同的概率为1−e−k(k−1)2n1-e^{-\frac{k(k-1)}{2n}}1−e−2nk(k−1)
忙活半天求这个概率的缩放值有啥目的呢?
为了证明当人稍微多一点,存在两个人生日同一天的概率就会变大,并且是超出直觉的大
比如n=365,求存在两个人生日相同的概率达到50%,至少需要几个人
1−e−k(k−1)730≥121-e^{-\frac{k(k-1)}{730}}\ge \frac{1}{2}\\ 1−e−730k(k−1)≥21k(k−1)≥730ln2=505.99744...≈506k(k-1)\ge 730\ln 2=505.99744...\approx 506 k(k−1)≥730ln2=505.99744...≈506
而23∗22=50623*22=50623∗22=506
因此k≥23k\ge 23k≥23
即至少23个人就可以
想想这个事情,随便路上找一个人比较生日,相同的概率只有1/365
但是随便找22个人都问一遍,就会有一半的概率,其中至少有一个人和我同生日
放在这里,求因数,怎么操作呢?
我们要产生一系列[2,N][2,\sqrt{N}][2,N]上的随机数,然后每次取一对做差检验这个差是不是N的因数
1.如何产生随机数
构造随机数函数f(x)=(x2+c)modnf(x)=(x^2+c)\mod nf(x)=(x2+c)modn,作用是生成随机数序列,其中c是随便指定的一个数,然后随便选取一个正整数x0x_0x0作为起点
x1=f(x0)=(x02+c)modnx2=f(x1)=(x12+c)modn...xm=f(xm−1)=(xm−12+c)modnx_1=f(x_0)=(x_0^2+c)\mod n\\ x_2=f(x_1)=(x_1^2+c)\mod n\\ ...\\ x_m=f(x_{m-1})=(x_{m-1}^2+c)\mod n x1=f(x0)=(x02+c)modnx2=f(x1)=(x12+c)modn...xm=f(xm−1)=(xm−12+c)modn
计算若干次后一定会陷入循环
为什么一定会陷入循环?
假设不会陷入循环,
则每一次计算都会得到一个与前面所有xix_ixi都不同的x值,但是∀xi∈[0,n−1]\forall x_i\in[0,n-1]∀xi∈[0,n−1],即xix_ixi顶多有n种取值,那么至多计算n次之后,由抽屉原理,一定会又两个xxx值相同.
假设是xj=f(f(f(f(...f(xi)))))x_j=f(f(f(f(...f(x_i)))))xj=f(f(f(f(...f(xi)))))即xix_ixi经过若干次迭代计算之后得到xjx_jxj,并且xi=xjx_i=x_jxi=xj
那么再计算xj+1=f(xj)=f(xi)=xi+1x_{j+1}=f(x_j)=f(x_i)=x_{i+1}xj+1=f(xj)=f(xi)=xi+1
以此类推可以得到xj+k=xi+kx_{j+k}=x_{i+k}xj+k=xi+k
显然陷入了循环
2.如何检查已经陷入了循环?
利用链表上快慢指针检查是否有环的思想
一个400米的圆形跑道,
两个傻子不知道跑道是⭕形状的,只知道沿着跑到一直跑
两个傻子同时同地起跑,快傻子每秒一米,慢傻子每秒半米,
相对速度差为每秒半米,那么经过800秒,相对路程差为800×0.5=400m800\times 0.5=400m800×0.5=400m,
快傻子正好比慢傻子快一圈,两人再次相遇表明"地球是圆的"即跑道是套圈的
在这里令xi=f(f(xi−1)),xj=f(xj−1)x_i=f(f(x_{i-1})),x_j=f(x_{j-1})xi=f(f(xi−1)),xj=f(xj−1),xix_ixi就是那个快傻子,xjx_jxj就是那个慢傻子,他俩就是那个海尔兄弟,舒克贝塔
并且两个傻子从并排起跑到再次相遇,他们的相对路程经理了一个从0到400的过程,遍历了[0,400][0,400][0,400]间的所有值
那么在这里两个快慢指针的差也就遍历了f(x)f(x)f(x)函数能够产生的,在圈上的,所有随机数的差
为啥说"在圈上的"
这里陷入循环不一定是从x0x_0x0就在循环中,
可能是中间某个状态才进入循环
就类似于一个ρ\rhoρ,一开始的xxx值是在ρ\rhoρ的"腿"上的,后来的xxx才进入ρ\rhoρ的圈上
这个方法叫做"Floyd判环"
当两个快慢指针再次相遇的时候,说明所有f(x)f(x)f(x)能够产生的圈上的随机数的差都不是NNN的因数
那么只能说明选的随机数函数真的太逊了
然后对f(x)=x2+cf(x)=x^2+cf(x)=x2+c进行修改比如修改一个初始值x0′x_0'x0′或者修改ccc或者直接修改函数表达式f(x)=x2+x+cf(x)=x^2+x+cf(x)=x2+x+c等等
3.最大公因数优化
刚才我们只是检查∣xi−xj∣|x_i-x_j|∣xi−xj∣能不能整除NNN,即检查∣xi−xj∣|x_i-x_j|∣xi−xj∣是不是NNN的因数
但是由于gcd(∣xi−xj∣,N)∣Nandgcd(∣xi−xj∣,N)∣∣xi−xj∣gcd(|x_i-x_j|,N)|N\ and\ gcd(|x_i-x_j|,N)||x_i-x_j|gcd(∣xi−xj∣,N)∣N and gcd(∣xi−xj∣,N)∣∣xi−xj∣,那么只要∣xi−xj∣|x_i-x_j|∣xi−xj∣是N的因数,那么gcd(∣xi−xj∣,N)gcd(|x_i-x_j|,N)gcd(∣xi−xj∣,N)也是N的因数
并且用最大公因数去和N比划的机会只会比只用∣xi−xj∣|x_i-x_j|∣xi−xj∣去直接比划N更多
对于∣xi−xj∣|x_i-x_j|∣xi−xj∣可以要求放松一点,只要是∣xi−xj∣|x_i-x_j|∣xi−xj∣的任何非1真因数能够整除NNN就算是给N找到了一个因数
完整代码
#include <iostream>
#include <algorithm>
using namespace std;long long gcd(const long long &a, const long long &b) {if (b == 0)return a;return gcd(b, a % b);
}long long f(const long long &x0, const long long &c, const long long &mod) {return (x0 * x0 % mod + c) % mod;
}long long Pollard_Rho(const long long &N) {long long c = rand() % (N - 1) + 1; //c∈[1,N-1]long long slow = f(0, c, N);long long fast = f(f(0, c, N), c, N);while (slow != fast) {long long d = gcd(abs(slow - fast), N);if (d > 1)return d;//找到N的真因数d,返回slow = f(slow, c, N);fast = f(f(fast, c, N), c, N);}return N;//失败
}
long long N;
int time = 0;int main() {while (cin >> N) {cout << ++time << ":";cout << Pollard_Rho(N) << endl;}
}
随便给几个数,这个程序的运行结果是怎样的呢?
8
1:8
8
2:4
8
3:8
8
4:4
8
5:8
8
6:8
9
7:9
9
8:9
9
9:9
9
10:3
可以发现,当N=8的时候,第一次失败了,第二次成功找到4,第三次又失败了,第四次又找到4,第五六次都失败了
当N=9,第九次失败,第十次找到三
如果真的失败了,多选上几个c去世或者改一下f函数去世.
如果试了很多次都失败了,就可以从概率上极大似然地认为N没有真因子了
BUUCTF-Alice和Bob
分解质因数985547997679855479976798554799767
还是运行刚才的程序
98554799767
1:98554799767
98554799767
2:101999
第二次就找到了真因子101999,我们只能确定他是985547997679855479976798554799767的因子,但是101999101999101999是不是素数还没有检查
但是吧101999101999101999用2,3,5,13,17这一些除一下都除不开,长成这样很像一个素数,98554799767/101999=96623398554799767/101999=96623398554799767/101999=966233,直接提交101999和966233就通过了
Pollard Rho算法分解因数相关推荐
- 大整数分解——Pollard Rho算法
延续上一篇,这次来讲一讲大整数分解算法的应用. 要解决的问题很简单,对一个整数进行分解质因数. 首先还是效率非常低的暴力算法,相信大家都会,不多提. 和上次一样,当数达到非常大的时候,分解将变得非常困 ...
- c语言用rho函数求复数模长,Pollard Rho 算法简介
$\text{update 2019.8.18}$ 由于本人将大部分精力花在了cnblogs上,而不是洛谷博客,评论区提出的一些问题直到今天才解决. 下面给出的Pollard Rho函数已给出散点图. ...
- BZOJ 5330 Luogu P4607 [SDOI2018]反回文串 (莫比乌斯反演、Pollard Rho算法)
题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=5330 (Luogu) https://www.luogu.org/prob ...
- 素数判定质因数分解(数论)(Miller Rabin)(Pollard Rho)
太玄学了! 我真的被概率的魅力折服了.此前我认为1便是1,0.9999999999-便是0.9999999999-. 但实际上它们有着千丝万缕的关系. 试想,如果一件事发生的概率是0.99999999 ...
- 因数分解 Pollard rho
因数分解 Pollard rho 算法思路 随机生成两个数a,ba,ba,b,然后求gcd(n,a−b)\gcd\pod{n,a-b}gcd(n,a−b),如果其值不为111,则这个数就是nnn的一 ...
- 【快速因数分解】Pollard's Rho 算法
算法目的 给一个数n,快速提取n的一个因数. 算法根据:生日悖论 讲生日悖论之前,先看一个东西. 给出[1-1000]的数,从中任意选出一个数为k的概率是110001\over 100010001. ...
- 2.2 基本算法之递归和自调用函数 1751 分解因数 python
http://noi.openjudge.cn/ch0202/1751/ """ 2.2 基本算法之递归和自调用函数 1751 分解因数 http://noi.openj ...
- 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方法是随机算法 ...
- 简述大数分解算法Pollard Rho和Pollard p-1
大数分解问题其实至今都是一个世界级难题,最常见的分解法是从2一直找到sqr(N),作为一个密码学专业的学生,每次看到别人这么做来进行因子分解,自己都控制不住想要制止他,因为这个算法的效率简直太太太太太 ...
最新文章
- Java项目:学生学科竞赛管理管理系统设计和实现(java+springboot+ssm+maven)
- 浅谈WebService的调用转
- 你需要知道的12个Git高级命令
- C++ string::size_type
- A Simple Note on P4FPGA: A Rapid Prototyping Framework for P4
- php 实现柱状图,PHP动态柱状图实现方法_PHP
- PySpark(一)
- LIS最长上升子序列详解+模板(dp和二分做法)
- 基于html + css + js完成淘宝网首页效果
- DOCTYPE声明——标准模式与怪异模式的区别
- Android手机减少微信步数,iPhone微信步数竟然比安卓少很多,原因已明确!
- 电脑硬件升级——笔记本更换更大容量的固态硬盘,并进行系统迁移
- 求任意两个整数的最大公因数
- springcloud springboot nacos版本对应
- 雨中的尾巴(线段树合并+树上差分)
- 亚马逊选品是单一产品好还是诸多产品好呢?
- 2009雷人语录最全
- Windows10常用快捷键汇总
- WebSSH安装和开机自启设置
- Revit二次开发入门关键
热门文章
- 如何在华为交换机上查询光模块DDM信息?
- 软件随想录(local.joelonsoftware.com/wiki)-2002年12月11日 程序设计领域的帕麦尔斯顿勋爵 - Lord Palmerston on Programming
- 如何查看自己的支付宝花呗是否已经接入央行征信? #花呗部分用户接入央行征信#
- 问题 E: LZY去年买了个表
- 使用健康档案数据计算OLT的用户光衰不合格率
- python实现图像格式转换(bmp、jpg、png)
- HDU 6232 2017 哈尔滨 Confliction
- 解决django admin表的外键关联数据过多响应时间过长问题
- E: The repository ‘http://ppa.launchpad.net/george-edison55/cmake-3.x/ubuntu bionic Release‘ does no
- python elif invalid syntax_Python错误集锦:if和elif语句提示:SyntaxError: invalid syntax