Official

C - Range Search Query Editorial by Nyaan Editorial for printing


この問題のポイントは、\(T\) の出現位置を前計算することでクエリを高速で処理することができるようになる点にあります。

以降では \(|S| = N, |T| = M\) とします。
各 \(i=1,2,\dots,N\) について \(A_i\) を以下のように定めます。

\[ A_i = \begin{cases} 1 & S の i 文字目から始まる長さ M の部分文字列が T と等しい \\ 0 & それ以外 \end{cases} \]

なお、\(i+M-1 \gt N\) の場合も \(A_i = 0\) です。
\(M\) が小さいので \(A_1, A_2, \dots, A_N\) の計算は \(\mathrm{O}(NM)\) で計算できます。

さらに、累積和 \(P_0, P_1, \dots, P_N\) を以下のように定義します。

\[P_0 = 0, P_i = \sum_{j=1}^i A_j\]

累積和テーブル \(P\) を用いることで、開始位置が区間 \([l, r]\) にある \(T\) の出現回数を

\[P_r - P_{l-1}\]

で計算できます。
\(P\) を用いてクエリに回答することを考えましょう。クエリで \(L,R\) が与えられた時、クエリ範囲の長さと \(M\) の大小で場合分けを行います。

(1) \(R - L + 1 \lt M\) の時

\(R - L + 1 \lt M\) の時、\(S\) の \(L\) 文字目から \(R\) 文字目までからなる部分文字列の長さは \(M\) 未満ですから、\(T\) を必ず含みません。よって答えは No です。

(2) \(R - L + 1 \geq M\) の時

\(R - L + 1 \geq M\) の時、\(S\) の \(L\) 文字目から \(R\) 文字目までからなる部分文字列の長さは \(M\) 以上です。
右端が \(S\) の \(R\) 文字目であるような長さ \(M\) の部分文字列の左端は \(S\) の \(R - M + 1\) 文字目であることを踏まえると、調べるべき開始位置 \(i\) は

\[ L \leq i \leq R - M + 1\]

の範囲です。よって \(P_{R-M+1} - P_{L-1} \gt 0\) であれば答えは Yes、そうでなければ答えは No となります。

以上の内容を実装すれば問題を \(\mathrm{O}(|S| |T|)\) で解くことが出来て、これは十分高速です。

posted:
last update: