library

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

View the Project on GitHub maspypy/library

:heavy_check_mark: string/rollinghash_2d.hpp

Depends on

Verified with

Code

#include "random/base.hpp"
#include "mod/modint61.hpp"

struct RollingHash_2D {
  using M61 = modint61;
  const M61 b1, b2;
  vc<M61> pow1;
  vc<M61> pow2;

  RollingHash_2D()
      : b1(generate_base()), b2(generate_base()), pow1{M61(1)}, pow2{M61(1)} {}

  template <typename STRING>
  vvc<M61> build(const vc<STRING>& S) {
    int H = len(S);
    int W = len(S[0]);
    vv(M61, res, H + 1, W + 1);
    FOR(x, H) {
      FOR(y, W) { res[x + 1][y + 1] = res[x + 1][y] * b2 + M61(S[x][y] + 1); }
      FOR(y, W + 1) res[x + 1][y] += b1 * res[x][y];
    }
    expand(pow1, b1, H);
    expand(pow2, b2, W);
    return res;
  }

  M61 query(const vvc<M61>& A, int xl, int xr, int yl, int yr) {
    assert(0 <= xl && xl <= xr && xr <= len(A));
    assert(0 <= yl && yl <= yr && yr <= len(A[0]));
    M61 a = A[xr][yr] - A[xr][yl] * pow2[yr - yl];
    M61 b = A[xl][yr] - A[xl][yl] * pow2[yr - yl];
    return a - b * pow1[xr - xl];
  }

private:
  static inline u64 generate_base() { return RNG(M61::get_mod()); }

  void expand(vc<M61>& pow, const M61& b, int n) {
    while (len(pow) <= n) pow.eb(pow.back() * b);
  }
};
#line 2 "random/base.hpp"

u64 RNG_64() {
  static uint64_t x_
      = uint64_t(chrono::duration_cast<chrono::nanoseconds>(chrono::high_resolution_clock::now().time_since_epoch()).count()) * 10150724397891781847ULL;
  x_ ^= x_ << 7;
  return x_ ^= x_ >> 9;
}

u64 RNG(u64 lim) { return RNG_64() % lim; }

ll RNG(ll l, ll r) { return l + RNG_64() % (r - l); }
#line 2 "mod/modint61.hpp"

struct modint61 {
  static constexpr u64 mod = (1ULL << 61) - 1;
  u64 val;
  constexpr modint61() : val(0ULL) {}
  constexpr modint61(u32 x) : val(x) {}
  constexpr modint61(u64 x) : val(x % mod) {}
  constexpr modint61(int x) : val((x < 0) ? (x + static_cast<ll>(mod)) : x) {}
  constexpr modint61(ll x) : val(((x %= static_cast<ll>(mod)) < 0) ? (x + static_cast<ll>(mod)) : x) {}
  static constexpr u64 get_mod() { return mod; }

  modint61 &operator+=(const modint61 &a) {
    val = ((val += a.val) >= mod) ? (val - mod) : val;
    return *this;
  }
  modint61 &operator-=(const modint61 &a) {
    val = ((val -= a.val) >= mod) ? (val + mod) : val;
    return *this;
  }
  modint61 &operator*=(const modint61 &a) {
    const unsigned __int128 y = static_cast<unsigned __int128>(val) * a.val;
    val = (y >> 61) + (y & mod);
    val = (val >= mod) ? (val - mod) : val;
    return *this;
  }
  modint61 operator-() const { return modint61(val ? mod - val : u64(0)); }
  modint61 &operator/=(const modint61 &a) { return (*this *= a.inverse()); }
  modint61 operator+(const modint61 &p) const { return modint61(*this) += p; }
  modint61 operator-(const modint61 &p) const { return modint61(*this) -= p; }
  modint61 operator*(const modint61 &p) const { return modint61(*this) *= p; }
  modint61 operator/(const modint61 &p) const { return modint61(*this) /= p; }
  bool operator<(const modint61 &other) const { return val < other.val; }
  bool operator==(const modint61 &p) const { return val == p.val; }
  bool operator!=(const modint61 &p) const { return val != p.val; }
  modint61 inverse() const {
    ll a = val, b = mod, u = 1, v = 0, t;
    while (b > 0) {
      t = a / b;
      swap(a -= t * b, b), swap(u -= t * v, v);
    }
    return modint61(u);
  }
  modint61 pow(ll n) const {
    assert(n >= 0);
    modint61 ret(1), mul(val);
    while (n > 0) {
      if (n & 1) ret *= mul;
      mul *= mul, n >>= 1;
    }
    return ret;
  }
};

#ifdef FASTIO
void rd(modint61 &x) {
  fastio::rd(x.val);
  assert(0 <= x.val && x.val < modint61::mod);
}

void wt(modint61 x) { fastio::wt(x.val); }
#endif
#line 3 "string/rollinghash_2d.hpp"

struct RollingHash_2D {
  using M61 = modint61;
  const M61 b1, b2;
  vc<M61> pow1;
  vc<M61> pow2;

  RollingHash_2D()
      : b1(generate_base()), b2(generate_base()), pow1{M61(1)}, pow2{M61(1)} {}

  template <typename STRING>
  vvc<M61> build(const vc<STRING>& S) {
    int H = len(S);
    int W = len(S[0]);
    vv(M61, res, H + 1, W + 1);
    FOR(x, H) {
      FOR(y, W) { res[x + 1][y + 1] = res[x + 1][y] * b2 + M61(S[x][y] + 1); }
      FOR(y, W + 1) res[x + 1][y] += b1 * res[x][y];
    }
    expand(pow1, b1, H);
    expand(pow2, b2, W);
    return res;
  }

  M61 query(const vvc<M61>& A, int xl, int xr, int yl, int yr) {
    assert(0 <= xl && xl <= xr && xr <= len(A));
    assert(0 <= yl && yl <= yr && yr <= len(A[0]));
    M61 a = A[xr][yr] - A[xr][yl] * pow2[yr - yl];
    M61 b = A[xl][yr] - A[xl][yl] * pow2[yr - yl];
    return a - b * pow1[xr - xl];
  }

private:
  static inline u64 generate_base() { return RNG(M61::get_mod()); }

  void expand(vc<M61>& pow, const M61& b, int n) {
    while (len(pow) <= n) pow.eb(pow.back() * b);
  }
};
Back to top page