This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub kmyk/competitive-programming-library
/**
* @brief a rolling hash
* @note 4 primes for modulo and and random bases
* @see http://hos.ac/blog/#blog0003
*/
struct rolling_hash {
static constexpr int size = 4;
static const int32_t prime[size];
static int32_t base[size];
static struct base_initializer_t {
base_initializer_t() {
random_device device;
default_random_engine gen(device());
REP (i, size) {
base[i] = uniform_int_distribution<int32_t>(256, prime[i] - 1)(gen);
}
}
} base_initializer;
public:
array<int32_t, size> data;
rolling_hash() : data({}) {}
rolling_hash(char c) {
REP (i, size) data[i] = c;
}
rolling_hash(const string & s) : data({}) {
for (char c : s) push_back(c);
}
void push_back(char c) {
REP (i, size) {
data[i] = (data[i] *(int64_t) base[i] + c) % prime[i];
}
}
rolling_hash & operator += (rolling_hash const & other) {
REP (i, size) {
data[i] += other.data[i];
if (data[i] >= prime[i]) data[i] -= prime[i];
}
return *this;
}
rolling_hash operator + (rolling_hash const & other) const {
return rolling_hash(*this) += other;
}
rolling_hash & operator -= (rolling_hash const & other) {
REP (i, size) {
data[i] -= other.data[i];
if (data[i] < 0) data[i] += prime[i];
}
return *this;
}
/**
* @note O(size)
*/
rolling_hash & operator <<= (array<int32_t, size> const & pow_base) {
REP (i, size) {
data[i] = data[i] *(int64_t) pow_base[i] % prime[i];
}
return *this;
}
/**
* @note O(size log width)
*/
rolling_hash & operator <<= (int width) {
array<int32_t, size> pow_base;
REP (i, size) {
pow_base[i] = powmod(base[i], width, prime[i]);
}
return *this << pow_base;
}
rolling_hash operator << (int width) const {
return rolling_hash(*this) <<= width;
}
bool operator == (rolling_hash const & other) const {
return data == other.data;
}
bool operator != (rolling_hash const & other) const {
return not (*this == other);
}
friend ostream & operator << (ostream & out, rolling_hash const & that) {
char buffer[8 * size + 1];
REP (i, size) {
sprintf(buffer + 8 * i, "%08x", that.data[i]);
}
return out << buffer;
}
};
const int32_t rolling_hash::prime[size] = { 1000000027, 1000000033, 1000000087, 1000000093 };
int32_t rolling_hash::base[size];
rolling_hash::base_initializer_t rolling_hash::base_initializer;
struct rolling_hash_cumulative_sum {
rolling_hash_cumulative_sum() = default;
int size;
vector<rolling_hash> data;
vector<array<int32_t, rolling_hash::size> > pow_base;
rolling_hash_cumulative_sum(string const & s) {
size = s.length();
data.resize(size + 1);
data[0] = rolling_hash();
REP (i, size) {
data[i + 1] = data[i];
data[i + 1].push_back(s[i]);
}
pow_base.resize(size + 1);
fill(ALL(pow_base[0]), 1);
REP (i, size) {
REP (j, rolling_hash::size) {
pow_base[i + 1][j] = pow_base[i][j] *(int64_t) rolling_hash::base[j] % rolling_hash::prime[j];
}
}
}
rolling_hash get_initial_segment(int r) {
assert (0 <= r and r <= size);
return data[r];
}
/**
* @note O(rolling_hash::size)
*/
rolling_hash get_range(int l, int r) {
assert (0 <= l and l <= r and r <= size);
return rolling_hash(data[r]) -= (rolling_hash(data[l]) <<= pow_base[r - l]);
}
};
/**
* @brief an adaptor to a segment tree
* @note slow
* @note you should use something like cumulative sum
*/
struct rolling_hash_monoid {
typedef struct { int length; rolling_hash hash; } value_type;
static value_type from_char(char c) {
return { 1, rolling_hash(c) };
}
value_type unit() const {
return { 0, rolling_hash() };
}
value_type append(value_type a, value_type const & b) const {
if (a.length == 0) return b;
if (b.length == 0) return a;
return { a.length + b.length, (a.hash <<= b.length) += b.hash };
}
};
constexpr uint64_t prime = 1000000000000037; // if you didn't shift
constexpr uint64_t base = 1009;
constexpr uint64_t prime = 1000000007;
constexpr uint64_t base = 10007;
uint64_t rolling_hash_push(uint64_t hash, int c) {
return (hash * base + c) % prime;
}
uint64_t rolling_hash_shift(uint64_t hash, int k) {
uint64_t e = base;
for (; k; k >>= 1) {
if (k & 1) hash = hash * e % prime;
e = e * e % prime;
}
return hash;
}
vector<uint64_t> rolling_hash_prepare(const vector<int> & s) {
vector<uint64_t> hash(s.size() + 1);
REP (i, s.size()) {
hash[i + 1] = rolling_hash_push(hash[i], s[i]);
}
return hash;
}
uint64_t rolling_hash_range(const vector<uint64_t> & hash, int l, int r) {
return (hash[r] - rolling_hash_shift(hash[l], r - l) + prime) % prime;
}
uint64_t rolling_hash(const vector<int> & s) {
uint64_t hash = 0;
for (int c : s) {
hash = rolling_hash_push(hash, c);
}
return hash;
}
#line 1 "old/rolling-hash.inc.cpp"
/**
* @brief a rolling hash
* @note 4 primes for modulo and and random bases
* @see http://hos.ac/blog/#blog0003
*/
struct rolling_hash {
static constexpr int size = 4;
static const int32_t prime[size];
static int32_t base[size];
static struct base_initializer_t {
base_initializer_t() {
random_device device;
default_random_engine gen(device());
REP (i, size) {
base[i] = uniform_int_distribution<int32_t>(256, prime[i] - 1)(gen);
}
}
} base_initializer;
public:
array<int32_t, size> data;
rolling_hash() : data({}) {}
rolling_hash(char c) {
REP (i, size) data[i] = c;
}
rolling_hash(const string & s) : data({}) {
for (char c : s) push_back(c);
}
void push_back(char c) {
REP (i, size) {
data[i] = (data[i] *(int64_t) base[i] + c) % prime[i];
}
}
rolling_hash & operator += (rolling_hash const & other) {
REP (i, size) {
data[i] += other.data[i];
if (data[i] >= prime[i]) data[i] -= prime[i];
}
return *this;
}
rolling_hash operator + (rolling_hash const & other) const {
return rolling_hash(*this) += other;
}
rolling_hash & operator -= (rolling_hash const & other) {
REP (i, size) {
data[i] -= other.data[i];
if (data[i] < 0) data[i] += prime[i];
}
return *this;
}
/**
* @note O(size)
*/
rolling_hash & operator <<= (array<int32_t, size> const & pow_base) {
REP (i, size) {
data[i] = data[i] *(int64_t) pow_base[i] % prime[i];
}
return *this;
}
/**
* @note O(size log width)
*/
rolling_hash & operator <<= (int width) {
array<int32_t, size> pow_base;
REP (i, size) {
pow_base[i] = powmod(base[i], width, prime[i]);
}
return *this << pow_base;
}
rolling_hash operator << (int width) const {
return rolling_hash(*this) <<= width;
}
bool operator == (rolling_hash const & other) const {
return data == other.data;
}
bool operator != (rolling_hash const & other) const {
return not (*this == other);
}
friend ostream & operator << (ostream & out, rolling_hash const & that) {
char buffer[8 * size + 1];
REP (i, size) {
sprintf(buffer + 8 * i, "%08x", that.data[i]);
}
return out << buffer;
}
};
const int32_t rolling_hash::prime[size] = { 1000000027, 1000000033, 1000000087, 1000000093 };
int32_t rolling_hash::base[size];
rolling_hash::base_initializer_t rolling_hash::base_initializer;
struct rolling_hash_cumulative_sum {
rolling_hash_cumulative_sum() = default;
int size;
vector<rolling_hash> data;
vector<array<int32_t, rolling_hash::size> > pow_base;
rolling_hash_cumulative_sum(string const & s) {
size = s.length();
data.resize(size + 1);
data[0] = rolling_hash();
REP (i, size) {
data[i + 1] = data[i];
data[i + 1].push_back(s[i]);
}
pow_base.resize(size + 1);
fill(ALL(pow_base[0]), 1);
REP (i, size) {
REP (j, rolling_hash::size) {
pow_base[i + 1][j] = pow_base[i][j] *(int64_t) rolling_hash::base[j] % rolling_hash::prime[j];
}
}
}
rolling_hash get_initial_segment(int r) {
assert (0 <= r and r <= size);
return data[r];
}
/**
* @note O(rolling_hash::size)
*/
rolling_hash get_range(int l, int r) {
assert (0 <= l and l <= r and r <= size);
return rolling_hash(data[r]) -= (rolling_hash(data[l]) <<= pow_base[r - l]);
}
};
/**
* @brief an adaptor to a segment tree
* @note slow
* @note you should use something like cumulative sum
*/
struct rolling_hash_monoid {
typedef struct { int length; rolling_hash hash; } value_type;
static value_type from_char(char c) {
return { 1, rolling_hash(c) };
}
value_type unit() const {
return { 0, rolling_hash() };
}
value_type append(value_type a, value_type const & b) const {
if (a.length == 0) return b;
if (b.length == 0) return a;
return { a.length + b.length, (a.hash <<= b.length) += b.hash };
}
};
constexpr uint64_t prime = 1000000000000037; // if you didn't shift
constexpr uint64_t base = 1009;
constexpr uint64_t prime = 1000000007;
constexpr uint64_t base = 10007;
uint64_t rolling_hash_push(uint64_t hash, int c) {
return (hash * base + c) % prime;
}
uint64_t rolling_hash_shift(uint64_t hash, int k) {
uint64_t e = base;
for (; k; k >>= 1) {
if (k & 1) hash = hash * e % prime;
e = e * e % prime;
}
return hash;
}
vector<uint64_t> rolling_hash_prepare(const vector<int> & s) {
vector<uint64_t> hash(s.size() + 1);
REP (i, s.size()) {
hash[i + 1] = rolling_hash_push(hash[i], s[i]);
}
return hash;
}
uint64_t rolling_hash_range(const vector<uint64_t> & hash, int l, int r) {
return (hash[r] - rolling_hash_shift(hash[l], r - l) + prime) % prime;
}
uint64_t rolling_hash(const vector<int> & s) {
uint64_t hash = 0;
for (int c : s) {
hash = rolling_hash_push(hash, c);
}
return hash;
}