Lam NguyenLibrary

Library · Strings · hashing

Rolling Hash

#pragma once
#include <bits/stdc++.h>
using namespace std;

using ll = long long;

class RollingHash {
private:
    ll base, mod;
    ll fwdhash, bwdhash;
    ll pow;
public:
    /*
        fwdhash = a0 * x^n + a1 * x^(n-1) + a2 * x^(n-2) + ... + an
        bwdhash = a0 + a1 * x + a2 * x^2 + ... + an * x^n
    */
    RollingHash() : base(313), mod(1e9+7), fwdhash(0), bwdhash(0), pow(1) {}
    RollingHash(ll base, ll mod) : base(base), fwdhash(0), bwdhash(0), pow(1) {}
    void push_back(ll c) {
        fwdhash = (fwdhash * base + c) % mod;
        bwdhash = (bwdhash + c * pow) % mod;
        pow = (pow * base) % mod;
    }
    void push_front(ll c) {
        fwdhash = (fwdhash + c * pow) % mod;
        bwdhash = (bwdhash * base + c) % mod;
        pow = (pow * base) % mod;
    }
    bool is_palindrome() {
        return fwdhash == bwdhash;
    }
    ll get_forward_hash() {
        return fwdhash;
    }
    ll get_backward_hash() {
        return bwdhash;
    }
    ll get_hash(int L, int R) {
        /*
            hash[R] 
                = s[0] * x^R + s[1] * x^(R-1) + .. + s[L-1] * x^(R-L+1) + s[L] * x^(R-L) + .. + s[R]
            hash[L] 
                = s[0] * x^L + s[1] * x^(L-1) + .. + s[L-1] * x^1 + s[L]
            hash[R+1] 
                = s[0] * x^(R+1) + s[1] * x^R + .. + s[L-1] * x^(R-L) + s[L] * x^(R-L+1) + .. + s[R] * x + s[R+1]
            hash[L] * x^(R-L+1)
                = s[0] * x^(R+1) + s[1] * x^R + .. + s[L-1] * x^(R-L) + s[L] * x^(R-L+1)
            hash(s[L..R]) = hash[R+1] - hash[L] * x^(R-L+1) 
                          = s[L+1] * x^(R-L) + .. + s[R] * x + s[R+1]

            note: hash[k] stores prefix hash length k of s[0..k-1]
        */
        return 0;
    }
};
class RollingHash:
    def __init__(self):
        self.base = 313
        self.mod = (1 << 61) - 1
        self.hash = [0]
        self.pow = [1]

    def push_back(self, c: str) -> int:
        self.hash.append((self.hash[-1] * self.base + ord(c)) % self.mod)
        self.pow.append(self.pow[-1] * self.base % self.mod)

    def get_hash(self, L: int = None, R: int = None) -> int:
        if L is None and R is None: return self.hash[-1]
        term = self.hash[L] * self.pow[R - L + 1] % self.mod
        return (self.hash[R + 1] + self.mod - term) % self.mod