This documentation is automatically generated by online-judge-tools/verification-helper
#include "src/string/rolling-hash.hpp"
#pragma once
#include <algorithm>
#include <cstdint>
#include <vector>
namespace luz {
struct RollingHash {
using u64 = std::uint64_t;
using u128 = __uint128_t;
static const u64 mod = (1ull << 61ull) - 1;
const u64 base;
std::vector< u64 > power;
static inline u64 add(u64 a, u64 b) {
if((a += b) >= mod) a -= mod;
return a;
}
static inline u64 mul(u64 a, u64 b) {
u128 c = u128(a) * b;
return add(c >> 61, c & mod);
}
inline void expand(int sz) {
int pre_sz = power.size();
if(pre_sz < sz + 1) {
power.resize(sz + 1);
for(int i = pre_sz - 1; i < sz; i++) {
power[i + 1] = mul(power[i], base);
}
}
}
RollingHash() : base(mod - 5), power{1} {}
template< class Iter >
std::vector< u64 > build(Iter f, Iter l) const {
std::vector< u64 > hs(1);
hs.reserve(l - f + 1);
while (f != l) {
u64 h = add(mul(hs.back(), base), *f);
hs.emplace_back(h);
++f;
}
return hs;
}
u64 query(const std::vector< u64 > &s, int l, int r) {
expand(r - l);
return add(s[r], mod - mul(s[l], power[r - l]));
}
u64 combine(u64 h1, u64 h2, size_t h2len) {
expand(h2len);
return add(mul(h1, power[h2len]), h2);
}
int lcp(const std::vector< u64 > &a, int l1, int r1,
const std::vector< u64 > &b, int l2, int r2) {
int len = std::min(r1 - l1, r2 - l2);
int low = 0, high = len + 1;
while (high - low > 1) {
int mid = (low + high) / 2;
if (query(a, l1, l1 + mid) == query(b, l2, l2 + mid)) low = mid;
else high = mid;
}
return low;
}
};
}
#line 2 "src/string/rolling-hash.hpp"
#include <algorithm>
#include <cstdint>
#include <vector>
namespace luz {
struct RollingHash {
using u64 = std::uint64_t;
using u128 = __uint128_t;
static const u64 mod = (1ull << 61ull) - 1;
const u64 base;
std::vector< u64 > power;
static inline u64 add(u64 a, u64 b) {
if((a += b) >= mod) a -= mod;
return a;
}
static inline u64 mul(u64 a, u64 b) {
u128 c = u128(a) * b;
return add(c >> 61, c & mod);
}
inline void expand(int sz) {
int pre_sz = power.size();
if(pre_sz < sz + 1) {
power.resize(sz + 1);
for(int i = pre_sz - 1; i < sz; i++) {
power[i + 1] = mul(power[i], base);
}
}
}
RollingHash() : base(mod - 5), power{1} {}
template< class Iter >
std::vector< u64 > build(Iter f, Iter l) const {
std::vector< u64 > hs(1);
hs.reserve(l - f + 1);
while (f != l) {
u64 h = add(mul(hs.back(), base), *f);
hs.emplace_back(h);
++f;
}
return hs;
}
u64 query(const std::vector< u64 > &s, int l, int r) {
expand(r - l);
return add(s[r], mod - mul(s[l], power[r - l]));
}
u64 combine(u64 h1, u64 h2, size_t h2len) {
expand(h2len);
return add(mul(h1, power[h2len]), h2);
}
int lcp(const std::vector< u64 > &a, int l1, int r1,
const std::vector< u64 > &b, int l2, int r2) {
int len = std::min(r1 - l1, r2 - l2);
int low = 0, high = len + 1;
while (high - low > 1) {
int mid = (low + high) / 2;
if (query(a, l1, l1 + mid) == query(b, l2, l2 + mid)) low = mid;
else high = mid;
}
return low;
}
};
}