关于 pollard's rho 的倍增实现

学术版

ppip @ 2023-05-10 22:45:30

本段代码来自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时退出吗?前者要更弱罢


by Alex_Wei @ 2023-05-11 00:07:16

@ppip 不用倍增,打包检查 gcd 也可以的,可以看我博客(cnblogs


by ppip @ 2023-05-11 21:17:32

@Alex_Wei 感谢,看完弄懂了


|