library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub maspypy/library

:heavy_check_mark: mod/O1_inverse.hpp

Verified with

Code

// https://qoj.ac/problem/5
// precompute O(p^{2/3}), query O(1)
// 10^8 query: 3sec
template <typename mint>
mint O1_inverse(int a) {
  /*
  n^3>=p となるように n をとり, n^2までは前計算.
  a/p を有理数近似する x/y. |a/p-x/y|<=|1/ny となると
  |ay-px|<=p/n<=n^2 より(ay)^{-1}が前計算されているのでできる.

  x/y は分母 n 未満の Farey 数列の前後どちらかが満たす.
  n^2 bucket に分割しておくと bucket ごとの有理数は distinct.
  前後のうち良い方を選べばよい.
  */
  static int p = 0;
  static double cp = 0.0;
  static vc<int> FRAC;
  static vc<mint> invs;
  if (p != mint::get_mod()) {
    p = mint::get_mod();
    int k = min(2 << 20, p);
    invs.resize(k);
    invs[1] = 1;
    FOR(i, 2, k) {
      int q = (p + i - 1) / i;
      invs[i] = invs[i * q - p] * mint::raw(q);
    }
    assert(p <= (1 << 30));
    FRAC.assign(1 << 20, -1);
    cp = 1.0 * (1 << 20) / p;
    for (int y = 1023; y >= 1; --y) {
      for (int x = 0; x < y; ++x) { FRAC[(x << 20) / y] = {x << 10 | y}; }
    }
    FOR(i, 1, len(FRAC)) if (FRAC[i] == -1) FRAC[i] = FRAC[i - 1];
    int nxt = 1025;
    FOR_R(i, 1, len(FRAC)) {
      if (FRAC[i] != FRAC[i - 1]) {
        nxt = FRAC[i];
        continue;
      }
      int x1 = FRAC[i] >> 10, y1 = FRAC[i] & 1023;
      int x2 = nxt >> 10, y2 = nxt & 1023;
      int c1 = i * y1 - (x1 << 20);
      int c2 = i * y2 - (x2 << 20);
      if (abs(c2) < abs(c1)) FRAC[i] = nxt;
    }
  }
  assert(0 <= a && a < p);
  if (a < len(invs)) return invs[a];

  int k = a * cp;
  ll x = FRAC[k] >> 10, y = FRAC[k] & 1023;
  int c = ll(a) * y - ll(p) * x;
  if (c < 0) c = -c, y = -y;
  return invs[c] * mint(y);
}
#line 1 "mod/O1_inverse.hpp"

// https://qoj.ac/problem/5
// precompute O(p^{2/3}), query O(1)
// 10^8 query: 3sec
template <typename mint>
mint O1_inverse(int a) {
  /*
  n^3>=p となるように n をとり, n^2までは前計算.
  a/p を有理数近似する x/y. |a/p-x/y|<=|1/ny となると
  |ay-px|<=p/n<=n^2 より(ay)^{-1}が前計算されているのでできる.

  x/y は分母 n 未満の Farey 数列の前後どちらかが満たす.
  n^2 bucket に分割しておくと bucket ごとの有理数は distinct.
  前後のうち良い方を選べばよい.
  */
  static int p = 0;
  static double cp = 0.0;
  static vc<int> FRAC;
  static vc<mint> invs;
  if (p != mint::get_mod()) {
    p = mint::get_mod();
    int k = min(2 << 20, p);
    invs.resize(k);
    invs[1] = 1;
    FOR(i, 2, k) {
      int q = (p + i - 1) / i;
      invs[i] = invs[i * q - p] * mint::raw(q);
    }
    assert(p <= (1 << 30));
    FRAC.assign(1 << 20, -1);
    cp = 1.0 * (1 << 20) / p;
    for (int y = 1023; y >= 1; --y) {
      for (int x = 0; x < y; ++x) { FRAC[(x << 20) / y] = {x << 10 | y}; }
    }
    FOR(i, 1, len(FRAC)) if (FRAC[i] == -1) FRAC[i] = FRAC[i - 1];
    int nxt = 1025;
    FOR_R(i, 1, len(FRAC)) {
      if (FRAC[i] != FRAC[i - 1]) {
        nxt = FRAC[i];
        continue;
      }
      int x1 = FRAC[i] >> 10, y1 = FRAC[i] & 1023;
      int x2 = nxt >> 10, y2 = nxt & 1023;
      int c1 = i * y1 - (x1 << 20);
      int c2 = i * y2 - (x2 << 20);
      if (abs(c2) < abs(c1)) FRAC[i] = nxt;
    }
  }
  assert(0 <= a && a < p);
  if (a < len(invs)) return invs[a];

  int k = a * cp;
  ll x = FRAC[k] >> 10, y = FRAC[k] & 1023;
  int c = ll(a) * y - ll(p) * x;
  if (c < 0) c = -c, y = -y;
  return invs[c] * mint(y);
}
Back to top page