JAG Summer Camp 2015 Day 2 F - ほぼ周期文字列
ローリングハッシュを使う。
文字列sとインデックスx,yが与えられたとき、sの接尾辞s[x..]とs[y..]のLCP(最長共通接頭辞)の長さをLCP(x,y)とする。sの区間[l,r)が周期tの文字列であることは、LCP(l,l+t)≥r−(l+t)であることと同値である。まず、これが成り立てばYes
を返してよい。
LCP(l,l+t)<r−(l+t)の場合、文字s[l+LCP(l,l+t)]とs[l+t+LCP(l,l+t)]が異なっている。一方の文字をもう一方の文字に変更すれば周期tの文字列になる可能性がある。
これを確かめるためには、連続部分列s[l..r−t]とs[l+t..r]について、s[l+LCP(l,l+t)]をs[l+t+LCP(l,l+t)]に変えたもの(あるいはその逆)のハッシュ値が等しいか調べればよい。
ローリングハッシュを初めて使った。例題と聞いて手をつけたのでLCPを使う方針はすぐに浮かんだが、正しい実装に時間がかかった。以下はメモ。
- ローリングハッシュに偽陽性(異なる文字列に対して同じハッシュ値を返す)はあるが偽陰性(一致する文字列に対して異なるハッシュ値を返す)はないので、2つの文字列を複数modで比較してひとつでもハッシュ値が異なれば異なる文字列である。
- LCPの場合、偽陽性は真の値より長い区間をLCPと判定するという形で現れるので、複数modによる最小値をLCPの長さとして採用すればよい。