本段代码来自oiwiki.
有如下朴素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);
}
return N;
}
oi-wiki上给出了如下的倍增优化:
ll Pollard_Rho(ll x) {
ll t = 0;
ll c = rand() % (x - 1) + 1;
// 加速算法,这一步可以省略
for (int i = 1; i < 1145; ++i) t = f(t, c, x);
ll s = t;
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;
// 如果 val 为 0,退出重新分解
if (!val) return 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;
}
}
我想问的是,优化的目的是减小gcd调用的次数,那直接每个一个间隔就把这一段枚举的|s-t|乘起来和n取gcd就行了吧,为什么要改成倍增形式?
另外,为什么遇到val=0退出?不应该是t=s时退出吗?前者要更弱罢