Loading

pollard-rho

补写算法流程。

生日悖论:值域为 \(n\),时,期望随机 \(O(\sqrt{n})\)(OI-wiki 上给的是 \(\sqrt{2 n \ln 2}\))个数有数字相同。(感觉有点奇怪,原表述是这么多次有数字相同的概率是 \(\frac{1}{2}\)。)

算法流程:

  • 尝试分解 \(n\) 的最小非平凡因子 \(m\)
  • \(f(x) = x^2 + c\),所有运算模 \(n\)\(x \equiv y, f(x) \equiv f(y)\)
  • 显然 \(f\) 最后会进入环,生成的东西就像 \(\rho\)
  • \(f(x)\) 看作随机数,则环的长度是 \(O(\sqrt{n})\) 级别。
  • \(m\) 若不是 \(n\),则 \(m\) 不大于 \(\sqrt{n}\)。把 \(f\) 中每一项对 \(m\) 取模,期望 \(O(n^{\frac{1}{4}})\) 次有重。故期望 \(O(n^{\frac{1}{4}})\) 种不同数字。
  • 随机选取 \(x_i, x_j\),有 \(\dfrac{1}{4}\) 概率 \(m \mid x_i-x_j\),此时提取 \(\gcd(n, |x_i-x_j|)\),是 \(m\) 的倍数。
  • 考虑判环,这里写倍增判环。每隔 \(2^i\) 步,找一个在序列中的基准点 \(t\),判 \(\prod (t - x_i)\) 是否为 \(0\)
  • \(\gcd\) 挺耗时间,隔一定间隔把要求 \(\gcd\) 的数字乘起来一起求也行。

挺对!

补写 MR 素性测试。

  • \(a^{n-1} \equiv 1 \pmod n\)\(n=p\) 时是对的,但是不能推出 \(n=p\)
  • \(a^2 \bmod p\) 两两成对,二次探测定理:\(x^2 \equiv 1 \pmod p\) 只有平凡解。
  • 考虑 \(a^{n-1} \equiv 1 \pmod n\)\(n\) 不是素数,把 \(n\) 分解为 \(2^u \cdot v\),逐一检测 \(a^{v \cdot 2^i}\),若出现 \(1\),则非平凡解出现,则 \(n\) 不是素数。
  • 我不大理解为什么这样留下来的很大概率是素数,但是它应当就是对的。

P4718:

#include <bits/stdc++.h>
#define LL long long

__int128 l = 1;

LL qpow(LL a, LL b, LL p) {
  LL ans = 1;
  for (; b; b >>= 1) {
    if (b & 1) ans = l * ans * a % p;
    a = l * a * a % p;
  }
  return ans;
}

std::default_random_engine e(time(0));
const int limmr = 8;
bool mr(LL n) {
  if (n % 2 == 0 && n > 2) return 0;
  if (n <= 3) return n != 1;
  LL u = n - 1, t = 0;
  while (u % 2 == 0) u /= 2, ++t;
  for (int i = 0; i < limmr; i++) {
    LL a = e() % (n - 2) + 2, v = qpow(a, u, n);
    if (v == 1 || v == n - 1) continue;
    LL s = 0;
    for (; s < t; ++s) {
      if (v == n - 1) break;
      v = l * v * v % n;
    }
    if (s == t) return 0;
  }
  return 1;
}

const int step = 127;
LL pr(LL n) {
  LL c = e() % (n - 1) + 1;
  LL t = 0, s = t;
  LL val = 1;
  for (LL lim = 1; ; lim <<= 1, t = s, val = 1) {
    for (LL st = 0; st < lim; ++st) {
      s = (l * s * s + c) % n;
      val = l * val * abs(t - s) % n;
      if (st % step == 0) {
        LL d = std::__gcd(val, n);
        if (d > 1) return d; // 期望 m^{1/4} 随到 p 倍数
      }
    }
    LL d = std::__gcd(val, n);
    if (d > 1) return d;
  }
}


LL maxfactor;
void fac(LL n) {
  if (n <= maxfactor || n == 1) return ;
  if (mr(n)) 
    return maxfactor = std::max(maxfactor, n), void();
  LL p = n;
  while (p >= n) p = pr(n);
  while (n % p == 0) n /= p;
  fac(p), fac(n);
}

int main() {
  int T; scanf("%d", &T); while (T--) {
    LL n; scanf("%lld", &n); 
    maxfactor = 0;
    if (!mr(n)) fac(n), printf("%lld\n", maxfactor);
    else printf("Prime\n");
  }
  return 0;
}
/*
stupid mistakes:
  - t=s 而非 s=t
  - __int128 那里打括号
*/
posted @ 2023-09-29 16:45  purplevine  阅读(26)  评论(0编辑  收藏  举报