问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Pollard Rho算法学习笔记:寻找大合数的非平凡因子

创作时间:
作者:
@小白创作中心

Pollard Rho算法学习笔记:寻找大合数的非平凡因子

引用
1
来源
1.
https://www.cnblogs.com/lupengheyyds/p/18781475

Pollard Rho算法是一种用于寻找大合数非平凡因子的算法。本文将从问题定义开始,逐步介绍算法的基本思想、实现方法和代码示例。

适用问题

现在我们要实现这样一个问题:对于一个大合数(n(n \approx 10^{18})),找到其任意一个非平凡因子(就是除去(1)和(n)的因子)。

一些朴素的想法

我会暴力!因为(n)是合数,其最小非平凡因子(p\le \sqrt n),所以直接遍历是(\mathcal O(\sqrt n))的复杂度,无法接受。

我会判断答案!我们发现,虽然找到一个因子(p)是很难的,但是给一个正整数(p)去判断其是否是(n)的因数是简单的,直接看判断(n\bmod p=0)。于是可以每次随机一个数并检验,这样下一次成功的概率为(\frac {d(n)}{n})而(\max_{i\le 10^{18}}d(i)\approx 10^5),则一次成功的概率约为(10^{-12}),这太低了。

我会 gcd!我们发现寻找两个数的 gcd 是有求解性(非判定性)的(\mathcal O(\log n))的算法的,于是只需要每次找一个数(p)然后判断(\gcd(p,n)>1)即可,这样最坏情况下一次成功概率为(\frac {1}{\sqrt n}=10^{-9}),要大了许多,但还是不够。

“一个数的因子不可求解而两个数的gcd却可快速求解”这一性质是 pollard rho 的关键。

pollard rho的初步思想

假设(n)的一个因子为(p),那么我们随便选择若干不重复正整数({x_i}),使得(\forall i,j,x_i\not\equiv x_j\pmod p)的概率为(\frac{p^{\underline {|{x_i}|}}}{p^{|{x_i}|}})。这是因为(|\Z_p|=p),根据生日悖论原理,我们期望取(\mathcal O(\sqrt p))个数时满足(\exists i,j,x_i\equiv x_j\pmod p),这时(\gcd(|x_i-x_j|,n))便是(n)的一个非平凡因子。

考虑将这样的随机过程确定下来,我们可以构造一个随机自映射(f:\Z_p\to \Z_p),即(f)映射再(\Z_p)上是确定的,即(\forall x\equiv y\pmod p,f(x)\equiv f(y)\pmod p)。

这样(x\leftarrow f(x))的过程走出了一个(\rho),成环的地方就是我们想要的。

然而根据(p)去构造(f)不现实,我们可以构造(f(x)=(x^2+c)\bmod n),其中(c)是一个([1,n])的随机数,来作为随机生成函数。而这样一个函数恰好满足需要的两个性质:

  • (\forall p|n,f)在(\Z_p)上随机。
  • (\forall p|n,f)满足自映射性质,证明显然。

现在就只需要考虑如何判断成环即可。

判环

假设两个人在赛跑,A 的速度快,B 的速度慢,经过一定时间后,A 一定会和 B 相遇,且相遇时 A 跑过的总距离减去 B 跑过的总距离一定是圈长的倍数。

一开始(a=b)每次(f(a)\to a,f(b)\to b)这样每次是需要检查(\gcd (|a-b|,n)>1),这说明在(\forall p|\gcd(|a-b|,n))的(\Z_p)上都成环了,而(\gcd (|a-b|,n))又正是我们想要的。

若(\gcd (|a-b|,n)=n)我们失败了,并且以后都不会成功,因为(\forall p|n,p)总是同时成环,这时就要重新随机一个(c)再次处理。设(p)为(n)的最小质因数,复杂度(\mathcal O(\sqrt p\log n))。

这种判环方法叫做 floyed 判环,需要对(n=4)的情况进行特判。

由于“倍增优化”只对brent 判环有正确性保证,这里就不介绍了。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,c;
mt19937_64 rnd(time(0));
int f(int x,int n){return ((__int128)x*x+c)%n;}
int pollard_rho(int n){
    if(n==4)return 2;//floyed判环刚好解决不了n=4的情况,这是一个巧合。 
    c=rnd()%n+1;
    int x=rnd()%n+1,a,b;a=b=x;
    while(true){
        a=f(a,n),b=f(f(b,n),n);
        if(__gcd(abs(a-b),n)>1)return __gcd(abs(a-b),n);
    }
}
signed main(){
    cin>>n;
    int x;
    do x=pollard_rho(n);while(x==n);
    cout<<x;
    return 0;
}
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号