C++ アルゴリズムとデータ構造のライブラリ
#include "library/string/rolling_hash.hpp"get(0, 5): 0~5文字目の部分文字列のハッシュを取得get: $O(1)$string S = "xxx";
RollingHash rh(S);
// ハッシュで比較
if (rh.get(0, 4) == rh.get(7, 11)) {}
string S = "xxxaaa";
RollingHash rh(S);
long long h_1 = rh.get(0, 2);
long long h_2 = rh.get(2, 5); // bの長さ3
// ハッシュをマージ
if (RollingHash::merge(h_1, h_2, 3) == rh.get(0, 5)) {}
#pragma once
#include "library/various/random.hpp"
struct RollingHash {
static const long long MOD = (1LL << 61) - 1;
static inline long long base = 0;
vector<long long> hash_sum;
// 基数をメルセンヌツイスタの乱数で初期化する
static void init_base() {
if (base != 0) return;
base = random(2, MOD - 1);
}
// 文字列からハッシュの累積和を構築する
RollingHash(const string &s) {
init_base();
int n = s.size();
hash_sum.assign(n + 1, 0);
for (int i = 0; i < n; i++) {
hash_sum[i + 1] = mul(hash_sum[i], base) + s[i];
if (hash_sum[i + 1] >= MOD) hash_sum[i + 1] -= MOD;
}
}
// 2^61-1 用の高速な掛け算
static long long mul(long long a, long long b) {
__int128_t res = (__int128_t)a * b;
long long ans = (long long)(res >> 61) + (long long)(res & MOD);
if (ans >= MOD) ans -= MOD;
return ans;
}
// 累乗テーブルの管理
static const vector<long long> &get_pow(int n) {
static vector<long long> pow_memo = {1};
while ((int)pow_memo.size() <= n) {
pow_memo.push_back(mul(pow_memo.back(), base));
}
return pow_memo;
}
// s[l, r) のハッシュを取得
long long get(int l, int r) const {
long long res = hash_sum[r] - mul(hash_sum[l], get_pow(r - l)[r - l]);
if (res < 0) res += MOD;
return res;
}
// 2つのハッシュ(a, b)を結合する。bの長さが b_len
static long long merge(long long a_hash, long long b_hash, int b_len) {
long long res = mul(a_hash, get_pow(b_len)[b_len]) + b_hash;
if (res >= MOD) res -= MOD;
return res;
}
};#line 2 "library/various/random.hpp"
#include <chrono>
#include <random>
inline long long random(long long a, long long b) {
if (a >= b) return a;
static mt19937 mt(chrono::steady_clock::now().time_since_epoch().count());
uniform_int_distribution<long long> dist(a, b - 1);
return dist(mt);
}
#line 3 "library/string/rolling_hash.hpp"
struct RollingHash {
static const long long MOD = (1LL << 61) - 1;
static inline long long base = 0;
vector<long long> hash_sum;
// 基数をメルセンヌツイスタの乱数で初期化する
static void init_base() {
if (base != 0) return;
base = random(2, MOD - 1);
}
// 文字列からハッシュの累積和を構築する
RollingHash(const string &s) {
init_base();
int n = s.size();
hash_sum.assign(n + 1, 0);
for (int i = 0; i < n; i++) {
hash_sum[i + 1] = mul(hash_sum[i], base) + s[i];
if (hash_sum[i + 1] >= MOD) hash_sum[i + 1] -= MOD;
}
}
// 2^61-1 用の高速な掛け算
static long long mul(long long a, long long b) {
__int128_t res = (__int128_t)a * b;
long long ans = (long long)(res >> 61) + (long long)(res & MOD);
if (ans >= MOD) ans -= MOD;
return ans;
}
// 累乗テーブルの管理
static const vector<long long> &get_pow(int n) {
static vector<long long> pow_memo = {1};
while ((int)pow_memo.size() <= n) {
pow_memo.push_back(mul(pow_memo.back(), base));
}
return pow_memo;
}
// s[l, r) のハッシュを取得
long long get(int l, int r) const {
long long res = hash_sum[r] - mul(hash_sum[l], get_pow(r - l)[r - l]);
if (res < 0) res += MOD;
return res;
}
// 2つのハッシュ(a, b)を結合する。bの長さが b_len
static long long merge(long long a_hash, long long b_hash, int b_len) {
long long res = mul(a_hash, get_pow(b_len)[b_len]) + b_hash;
if (res >= MOD) res -= MOD;
return res;
}
};