2019年6月24日月曜日

JAG Summer Camp 2015 Day 2 F - ほぼ周期文字列

JAG Summer Camp 2015 Day 2 F - ほぼ周期文字列

ローリングハッシュを使う。

文字列ssとインデックスx,yx, yが与えられたとき、ssの接尾辞s[x..]s[x..]s[y..]s[y..]のLCP(最長共通接頭辞)の長さをLCP(x,y)\operatorname{LCP}(x, y)とする。ssの区間[l,r)[l, r)が周期ttの文字列であることは、LCP(l,l+t)r(l+t)\operatorname{LCP}(l, l+t) \ge r-(l+t)であることと同値である。まず、これが成り立てばYesを返してよい。

LCP(l,l+t)<r(l+t)\operatorname{LCP}(l, l+t) < r-(l+t)の場合、文字s[l+LCP(l,l+t)]s[l+\operatorname{LCP}(l, l+t)]s[l+t+LCP(l,l+t)]s[l+t+\operatorname{LCP}(l, l+t)]が異なっている。一方の文字をもう一方の文字に変更すれば周期ttの文字列になる可能性がある。

これを確かめるためには、連続部分列s[l..rt]s[l .. r-t]s[l+t..r]s[l+t .. r]について、s[l+LCP(l,l+t)]s[l+\operatorname{LCP}(l, l+t)]s[l+t+LCP(l,l+t)]s[l+t+\operatorname{LCP}(l, l+t)]に変えたもの(あるいはその逆)のハッシュ値が等しいか調べればよい。


ローリングハッシュを初めて使った。例題と聞いて手をつけたのでLCPを使う方針はすぐに浮かんだが、正しい実装に時間がかかった。以下はメモ。

  • ローリングハッシュに偽陽性(異なる文字列に対して同じハッシュ値を返す)はあるが偽陰性(一致する文字列に対して異なるハッシュ値を返す)はないので、2つの文字列を複数modで比較してひとつでもハッシュ値が異なれば異なる文字列である。
  • LCPの場合、偽陽性は真の値より長い区間をLCPと判定するという形で現れるので、複数modによる最小値をLCPの長さとして採用すればよい。