-
Notifications
You must be signed in to change notification settings - Fork 3
/
rolling_hash.h
98 lines (77 loc) · 2.65 KB
/
rolling_hash.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#pragma once
#include "singleton.h"
#include "zip_with.h"
#include <iostream>
#include <random>
#include <tuple>
#include <type_traits>
#include <utility>
template <typename... Mods> struct RollingHashT {
using Hash = std::tuple<Mods...>;
template <typename Gen> static void initialize(Gen &gen, int reserved = 0) {
singleton<SeedStore>().set_seed(gen, reserved);
}
static Hash seed() { return singleton<SeedStore>().powers[1]; }
explicit RollingHashT() = default;
explicit RollingHashT(const Hash &hash_, int length_ = 1)
: hash{hash_}, length{length_} {}
template <typename T>
explicit RollingHashT(T v)
: hash{make_with([v]<typename Mod>(Mod) { return Mod{v}; })}, length{1} {
static_assert(std::is_integral_v<T>);
}
bool operator==(const RollingHashT &o) const { return hash == o.hash; }
bool operator<(const RollingHashT &o) const { return get() < o.get(); }
RollingHashT operator+(const RollingHashT &o) const {
return RollingHashT{
zip_with([]<typename Mod>(Mod h, Mod p, Mod oh) { return h * p + oh; },
hash, singleton<SeedStore>().get_power(o.length), o.hash),
length + o.length};
}
RollingHashT operator-(const RollingHashT &o) const {
return RollingHashT{
zip_with([]<typename Mod>(Mod h, Mod oh, Mod p) { return h - oh * p; },
hash, o.hash,
singleton<SeedStore>().get_power(length - o.length)),
length - o.length};
}
Hash hash;
int length;
private:
template <typename Fun> static inline Hash make_with(Fun &&fun) {
return zip_with(std::forward<Fun>(fun), Hash{});
}
auto get() const {
return zip_with([]<typename Mod>(Mod h) { return h.get(); }, hash);
}
struct SeedStore {
template <typename Gen> void set_seed(Gen &gen, int r) {
auto one = make_with([]<typename Mod>(Mod) { return Mod::mul_id(); });
auto seed = make_with([&gen]<typename Mod>(Mod) {
return Mod{std::uniform_int_distribution<typename Mod::M>{
0, Mod::mod() - 1}(gen)};
});
powers = {one, seed};
get_power(r);
}
Hash get_power(int n) {
auto old_size = powers.size();
if (old_size <= n) {
powers.resize(n + 1);
for (int i = old_size; i <= n; ++i) {
powers[i] =
zip_with([]<typename Mod>(Mod x, Mod y) -> Mod { return x * y; },
powers[i - 1], powers[1]);
}
}
return powers[n];
}
std::vector<Hash> powers;
};
};
namespace std {
template <typename... Mods>
ostream &operator<<(ostream &out, const RollingHashT<Mods...> &h) {
return out << h.hash << ':' << h.length;
}
} // namespace std