template times*(n:int,body) = (for _ in 0.." ,discardable.} proc scan(): int = while true: let k = getchar_unlocked() if k < '0': return result = 10 * result + k.ord - '0'.ord type SuffixArray* = ref object S* : string SA*: seq[int] LCP*: seq[int] proc SAIS(inputString:string) : seq[int] = proc SAISImpl(S:seq[int], k:int):seq[int] = # https://blog.knshnb.com/posts/sa-is/ let n = S.len # [1..255] までのbyte文字しかでないはず # 1. S, L, LMS var isS = newSeq[bool](n) isS[n-1] = true var isLMS = newSeq[bool](n) var LMSS = newSeq[int]() for i in (n-2).countdown(0): isS[i] = S[i] < S[i+1] or (S[i] == S[i+1] and isS[i + 1]) for i in 0.. 1: rank += 1 pseudoSA[orderedLMSS[1]] = rank for i in 1.. 0 and isLMS[p] : break if isDiff: rank += 1 pseudoSA[orderedLMSS[i+1]] = rank var newS = newSeq[int](LMSS.len()) index = 0 for i in 0.. 0 : var j = result.SA[B[i]-1] while j + h < n and i + h < n and S[j+h] == S[i+h]: h += 1 result.LCP[B[i]] = h if h > 0 : h -= 1 result.LCP[0] = -1 # O(Plog|S|) proc lowerBound*(self:SuffixArray,prefix:string): tuple[index:int,isMatched:bool] = # i := {S} >= prefix の最小の位置を返却 var now = -1..self.S.len + 1 while now.a + 1 < now.b: let m = (now.a + now.b) shr 1 let start = self.SA[m] if self.S[start..= self.SA.len: return (found,false) let start = self.SA[found] let isMatched = self.S[start..