use crate::{
number_theory::modint_for_rollinghash::modint::Modint,
utils::num_traits::{One, Zero},
};
#[derive(Debug)]
pub struct RollingHash {
pub size: usize,
power: Vec<Modint>,
hash: Vec<Modint>,
base: Modint,
}
impl RollingHash {
pub fn build(arr: &[Modint], base: Modint) -> Self {
let size = arr.len();
let mut power = vec![Modint(1); size + 1];
let mut hash = vec![Modint(0); size + 1];
let (mut h, mut p) = (Modint::zero(), Modint::one());
for i in 0..size {
h = arr[i] + (h * base);
p *= base;
hash[i + 1] = h;
power[i + 1] = p;
}
Self {
size,
power,
hash,
base,
}
}
pub fn from_str(s: &str, base: Modint) -> Self {
let arr: Vec<Modint> = s.chars().map(Self::ord).map(Modint).collect();
Self::build(&arr, base)
}
pub fn get(&self, l: usize, r: usize) -> Modint {
self.hash[r] - self.hash[l] * self.power[r - l]
}
pub fn full(&self) -> Modint {
self.hash[self.size]
}
pub fn getLCP(&self, a: usize, b: usize) -> usize {
let len = self.size.saturating_sub(a.max(b));
let (mut lo, mut hi) = (0, len + 1);
while hi - lo > 1 {
let mid = (lo + hi) / 2;
if self.get(a, a + mid) == self.get(b, b + mid) {
lo = mid;
} else {
hi = mid;
}
}
lo
}
pub fn concat(&self, h1: Modint, h2: Modint, h2_len: usize) -> Modint {
h1 * self.power[h2_len] + h2
}
#[inline]
fn ord(c: char) -> usize {
let a = 'A' as u32;
let c = c as u32;
(c - a) as usize
}
}