Thanks to visit codestin.com
Credit goes to hitonanode.github.io

cplib-cpp

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

View the Project on GitHub hitonanode/cplib-cpp

:heavy_check_mark: Rolling hash (two dimensional) (二次元ローリングハッシュ)
(string/rolling_hash_2d.hpp)

行列に対する典型的なローリングハッシュ.構築・矩形取得が線形時間で可能.

使用方法

using Hash = ModIntMersenne61;

vector<string> mat;
rolling_hash_2d<Hash> rh(mat)

int xl, xr, yl, yr;
Hash h = rh.get(xl, xr, yl, yr);  // [xl, xr) * [yl, yr) のハッシュ値を取得する

ハッシュの型 PairHashTupleHash3 は任意に入れ子にすることも可能で,例えば

using Hash = ModIntMersenne61;
using Hash = TupleHash3<ModInt998244353, ModInt998244353, ModInt998244353>;
using PH = PairHash<ModInt998244353, ModInt998244353>;
using Hash = TupleHash3<PH, ModInt998244353, PH>;
using Hash = PairHash<PH, PairHash<ModInt998244353, ModInt998244353>>;

は全て動作する.

Verified with

Code

#pragma once
#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 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];
    }
};
Back to top page