スパークリング黒ココア/黒ココア式RollingHash

Created Tue, 10 Jan 2023 Modified Tue, 26 Sep 2023 09:13:30 +0000

ソースコード

  • 正直、これをPython移植しただけのやつ
  • あんまり中身が何してるのかはわかってないけど、爆速、っぽい…
    • 参考
    • (1<<61)-1 $= 2305843009213693951 > 2 \times 10^{18}$
class BlackCocoaRollingHash():
    def __init__(self, s, base=37, mod=(1 << 61) - 1):
        self.mask30 = (1 << 30) - 1
        self.mask31 = (1 << 31) - 1
        self.mod = mod
        self.base = base
        self.mask61 = (1 << 61) - 1
        self.positivizer = self.mod * ((1 << 3) - 1)
        l = len(s)
        self.pw = pw = [1] * (l + 1)
        self.h = h = [0] * (l + 1)
        v = 0
        for i in range(l):
            self.h[i + 1] = v = self.calcmod(self.mul(v, base) + ord(s[i]))
        v = 1
        for i in range(l):
            self.pw[i + 1] = v = self.calcmod(self.mul(v, base))

    def get(self, start, length):
        return self.calcmod(self.h[start + length] + self.positivizer - self.mul(self.h[start], self.pw[length]))

    def mul(self, a, b):
        au = a >> 31
        ad = a & self.mask31
        bu = b >> 31
        bd = b & self.mask31
        mid = ad * bu + au * bd
        midu = mid >> 30
        midd = mid & self.mask30
        return self.calcmod(au * bu * 2 + midu + (midd << 31) + ad * bd)

    def calcmod(self, x):
        xu = x >> 61
        xd = x & self.mask61
        res = xu + xd
        if res >= self.mod:
            res -= self.mod
        return res