[学习笔记]Pollard Rho算法
问题
\(N \in N^{+}\),试快速处理出其一个因数。
生日悖论
考虑把每个人的生日写作一个正整数,才能使其中两个人生日相同的概率大于\(50%\)。
假设一年中有 \(n\) 天,房间 \(k\) 人,用整数\(1,2,....,k\)对这些人进行编号,假定每个人的生日均匀分布于\(n\)天之中,且两个人的生日相互独立。
设\(k\)个人生日互不相同为事件\(A\),则事件\(A\)的概率为
\(P(A) = \prod_{i = 1} ^ k \frac{n - i + 1}{n}\)
那么知\(P(A) \leq \frac{1}{2}\)
知\(1 + x \leq e ^ x\)
\(P(A) \leq \prod_{i = 1}^k e^{\frac{1 - i}{e}} = e^{-\frac{k * (k - 1)}{2n}}\leq \frac{1}{2}\)
若一年有\(n\)天,其房间里有\(\sqrt n\)个人时满足条件。
构造伪随机函数
我们通过\(f(x) = (x^2 + c) \ mod\ n\)来生成一个随机数序列\(x_i\),其中\(c = rand()\),是一个随机的常数。
随机取\(x_1\),令\(x_2 = f(x_1),x_3 = f(x_2) .... x_i = f(x_{i - 1}])\)。
优化随机算法
最大公约数一定是某个数的约数,即\(\forall k \in N^{+},gcd(k,n) | n\),只要选适当的 \(k\) 使得 \(1 < gcd(k,n) < n\)就可以求得一个约数 \(gcd(k,n)\)。
将生日悖论应用到随机算法中,伪随机数列中不同值的数量的约为\(O(\sqrt n)\)个,设\(m\)为\(n\)的最小的非平凡银子,显然有\(m\leq\sqrt n\)则有 \(y_i = x_i (mod\ m)\)
那么有\(y_{i + 1} = x_{i + 1}\ mod\ m = y_i ^ 2 + c (\ mod\ m)\)
所以其不同的数有\(O(\sqrt m) \leq O(n^{\frac{1}{4}})\)
如果有\(x_i \neq x_j \land y_i = y_j\),这意味着\(n \nmid |x_i - x_j| \land m | |x_i - x_j|\),所以我们可以通过\(gcd(n,|x_i - x_j|)\)获得\(n\)的一个平凡因子。
时间复杂度分析
\(O(\sqrt m)\)
实现
Floyd判环
设\(a = f(1),b = f(f(1))\),每一次更新为\(a = f(a),b = f(f(b))\),只要检查在更新过程\(a,b\)是否等于环,每次检查\(gcd(|x_i - x_j|,n)\)是否满足条件。
Floyd判环
ll Pollard _Rho(ll n){
ll c = rand() % (n - 1) + 1;
ll t = f(0,c,n);
ll r = f(f(0,c,n),c,n);
while(t != r){
ll d = gcd(abs(t - r),n);
if(d > 1)return d;
t = f(t,c,n);
r = f(f(r,c,n),c,n);
}
}
倍增优化
使用\(gcd\)过程太多次会让算法变慢。
我们通过乘法减少次数
我们\(gcd(ac\ mod\ b,b) = gcd(a,b)\)
我们设\(s = \prod |x0 - x_j|\ mod\ n\),我们隔\(2^k - 1\)个数,计算是否满足\(1 < gcd(s,n) < n\),取 $ k = 7$
倍增优化
ll Pollard_Rho(ll x) {
ll s = 0, t = 0;
ll c = rand() % (x - 1) + 1;
int step = 0, goal = 1;
ll val = 1;
for (goal = 1;; goal <<= 1, s = t, val = 1) {
for (step = 1; step <= goal; ++step) {
t = f(t, c, x);
val = val * abs(t - s) % x;
if ((step % 127) == 0) {
ll d = gcd(val, x);
if (d > 1) return d;
}
}
ll d = gcd(val, x);
if (d > 1) return d;
}
}