This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub hitonanode/cplib-cpp
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_14_C" #include "../../number/modint_mersenne61.hpp" #include "../rolling_hash_2d.hpp" #include <iostream> #include <string> #include <vector> using namespace std; int main() { cin.tie(nullptr), ios::sync_with_stdio(false); int H, W; cin >> H >> W; vector<string> S(H); for (auto &s : S) cin >> s; int X, Y; cin >> X >> Y; vector<string> T(X); for (auto &t : T) cin >> t; const ModIntMersenne61 b1(418672), b2(956731); rolling_hash_2d<ModIntMersenne61> rhs(S, b1, b2); const auto tgt = rolling_hash_2d<ModIntMersenne61>(T, b1, b2).get(0, X, 0, Y); for (int i = 0; i + X <= H; ++i) { for (int j = 0; j + Y <= W; ++j) { if (rhs.get(i, i + X, j, j + Y) == tgt) cout << i << ' ' << j << '\n'; } } }
#line 1 "string/test/rolling_hash_2d.aoj.test.cpp" #define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_14_C" #line 2 "number/modint_mersenne61.hpp" #include <cassert> #include <chrono> #include <random> // F_p, p = 2^61 - 1 // https://qiita.com/keymoon/items/11fac5627672a6d6a9f6 class ModIntMersenne61 { static const long long md = (1LL << 61) - 1; long long _v; inline unsigned hi() const noexcept { return _v >> 31; } inline unsigned lo() const noexcept { return _v & ((1LL << 31) - 1); } public: static long long mod() { return md; } ModIntMersenne61() : _v(0) {} // 0 <= x < md * 2 explicit ModIntMersenne61(long long x) : _v(x >= md ? x - md : x) {} long long val() const noexcept { return _v; } ModIntMersenne61 operator+(const ModIntMersenne61 &x) const { return ModIntMersenne61(_v + x._v); } ModIntMersenne61 operator-(const ModIntMersenne61 &x) const { return ModIntMersenne61(_v + md - x._v); } ModIntMersenne61 operator*(const ModIntMersenne61 &x) const { using ull = unsigned long long; ull uu = (ull)hi() * x.hi() * 2; ull ll = (ull)lo() * x.lo(); ull lu = (ull)hi() * x.lo() + (ull)lo() * x.hi(); ull sum = uu + ll + ((lu & ((1ULL << 30) - 1)) << 31) + (lu >> 30); ull reduced = (sum >> 61) + (sum & ull(md)); return ModIntMersenne61(reduced); } ModIntMersenne61 pow(long long n) const { assert(n >= 0); ModIntMersenne61 ans(1), tmp = *this; while (n) { if (n & 1) ans *= tmp; tmp *= tmp, n >>= 1; } return ans; } ModIntMersenne61 inv() const { return pow(md - 2); } ModIntMersenne61 operator/(const ModIntMersenne61 &x) const { return *this * x.inv(); } ModIntMersenne61 operator-() const { return ModIntMersenne61(md - _v); } ModIntMersenne61 &operator+=(const ModIntMersenne61 &x) { return *this = *this + x; } ModIntMersenne61 &operator-=(const ModIntMersenne61 &x) { return *this = *this - x; } ModIntMersenne61 &operator*=(const ModIntMersenne61 &x) { return *this = *this * x; } ModIntMersenne61 &operator/=(const ModIntMersenne61 &x) { return *this = *this / x; } ModIntMersenne61 operator+(unsigned x) const { return ModIntMersenne61(this->_v + x); } bool operator==(const ModIntMersenne61 &x) const { return _v == x._v; } bool operator!=(const ModIntMersenne61 &x) const { return _v != x._v; } bool operator<(const ModIntMersenne61 &x) const { return _v < x._v; } // To use std::map template <class OStream> friend OStream &operator<<(OStream &os, const ModIntMersenne61 &x) { return os << x._v; } static ModIntMersenne61 randgen(bool force_update = false) { static ModIntMersenne61 b(0); if (b == ModIntMersenne61(0) or force_update) { std::mt19937 mt(std::chrono::steady_clock::now().time_since_epoch().count()); std::uniform_int_distribution<long long> d(1, ModIntMersenne61::mod()); b = ModIntMersenne61(d(mt)); } return b; } }; #line 2 "string/rolling_hash_2d.hpp" #include <string> #include <vector> // Rolling Hash (Rabin-Karp), 2dim template <typename V> struct rolling_hash_2d { const V Bx, By; std::vector<V> powx, powy; // powx[i] = Bx^i std::vector<std::vector<V>> hash; void gen_pow(int h, int w) { powx.assign(h + 1, V(1)); for (int i = 1; i <= h; ++i) powx.at(i) = powx.at(i - 1) * Bx; powy.assign(w + 1, V(1)); for (int i = 1; i <= w; ++i) powy.at(i) = powy.at(i - 1) * By; } inline V _at(int x, int y) const noexcept { if (x < 0 or x >= int(hash.size())) return V(); if (y < 0 or y >= int(hash[x].size())) return V(); return hash[x][y]; } template <typename Int> void build(const std::vector<std::vector<Int>> &s) { const int H = s.size(), W = H ? s.at(0).size() : 0; gen_pow(H, W); hash.assign(H, std::vector<V>(W, V())); for (int i = 0; i < H; ++i) { for (int j = 0; j < W; ++j) hash[i][j] = _at(i, j - 1) * By + s[i][j]; } for (int i = 0; i < H; ++i) { for (int j = 0; j < W; ++j) hash[i][j] = hash[i][j] + _at(i - 1, j) * Bx; } } template <typename Int> rolling_hash_2d(const std::vector<std::vector<Int>> &s, V bx, V by) : Bx(bx), By(by) { build(s); } rolling_hash_2d(const std::vector<std::string> &m, V bx, V by) : Bx(bx), By(by) { std::vector<std::vector<int>> v_; for (const auto &s : m) { v_.push_back({}); for (char c : s) v_.back().push_back(int(c)); } build(v_); } V get(int xl, int xr, int yl, int yr) const { return _at(xr - 1, yr - 1) - _at(xl - 1, yr - 1) * powx[xr - xl] - _at(xr - 1, yl - 1) * powy[yr - yl] + _at(xl - 1, yl - 1) * powx[xr - xl] * powy[yr - yl]; } }; #line 4 "string/test/rolling_hash_2d.aoj.test.cpp" #include <iostream> #line 8 "string/test/rolling_hash_2d.aoj.test.cpp" using namespace std; int main() { cin.tie(nullptr), ios::sync_with_stdio(false); int H, W; cin >> H >> W; vector<string> S(H); for (auto &s : S) cin >> s; int X, Y; cin >> X >> Y; vector<string> T(X); for (auto &t : T) cin >> t; const ModIntMersenne61 b1(418672), b2(956731); rolling_hash_2d<ModIntMersenne61> rhs(S, b1, b2); const auto tgt = rolling_hash_2d<ModIntMersenne61>(T, b1, b2).get(0, X, 0, Y); for (int i = 0; i + X <= H; ++i) { for (int j = 0; j + Y <= W; ++j) { if (rhs.get(i, i + X, j, j + Y) == tgt) cout << i << ' ' << j << '\n'; } } }