目次

AtCoder Beginner Contest 246 Ex問題メモ

AtCoder Beginner Contest 246

Ex - 01? Queries

Ex - 01? Queries

問題

解法

DPの遷移が、小さな行列の積で表現できることを利用して、行列を乗せたセグメント木で必要な箇所だけを更新する。

公式Editorialでは3×3の行列を用いていた。その方が自然なので、基本的にそちらを参照すればよい。

4×4の行列を使って解いたので、考えだけメモ。

$j$ は、以下の4つの状態の分類とする。

それぞれの状態から、$S$ の $i+1$ 文字目が '0','1','?' のそれぞれの場合だったときに、 「それを末尾に採用したとき(採用したら新しい文字列となる場合のみ)」「採用しなかったとき」で、遷移先が一意に定まる。

   0                1                ?                    遷移先
   oo ox xo xx      oo ox xo xx      oo ox xo xx          ------→
oo [1, 0, 1, 0],    [1, 1, 0, 0],    [2, 0, 0, 1],    遷|
ox [1, 0, 0, 1],    [0, 1, 0, 0],    [1, 0, 0, 1],    移|
xo [0, 0, 1, 0],    [1, 0, 0, 1],    [1, 0, 0, 1],    元|
xx [0, 0, 0, 1],    [0, 0, 0, 1],    [0, 0, 0, 1],      ↓

大まかには、「先頭 $i$ 文字から作れる部分列の集合」を $B_i$ として、

あとは $S$ の各文字に対応する行列を先頭からかけ算していった結果で、1行目の和が答えとなる(初期状態の空文字列は oo にあたるので)。
ただし結果には空文字列も含まれるため、最後に -1 する。

セグメント木の実装に注意。行列積は左項と右項の順番で答えが変わるので、ここを蔑ろにした実装では正しい答えが求まらない。

行列積の計算量はサイズの3乗で利いてくるので、$3^3=27$ と $4^3=64$ では2倍以上効率が悪いが、Pythonでもギリギリで通った。

Python3