Official

G - Edit to Match Editorial by sounansya


以下のような動的計画法を考えます。

\(d_k[T]=(\) 空文字列、 \(S_1,S_2,\ldots,S_{k-1}\) のうち \(T\) が接頭辞であるような文字列の長さの最小値、ただし存在しないなら \(\infty\) \()\)

\(k=0\) では \(T\) が空文字列なら \(d_0[T]=0\) 、空文字列でないなら \(d_0[T]=\infty\) とします。

\(d_{k-1}\) から \(d_k\) への遷移を考えると、 \(i=1,2,\ldots,|S_k|\) に対し \(d_{k}[S_k[:i]] \leftarrow \min(d_{k}[S_k[:i]] , |S_k|)\) となります。ここで、 \(S_k[:i]\)\(S_k\)\(i\) 文字目までの文字列です。

この文字列を直接添字に持つと TLE してしまいますが、 Trie として木で持ちながら in-place に更新することで空間計算量 \(\displaystyle O\left(\sum_{k=1}^N |S_k| \right)\) で値を持つことができます。Trie として持つと上で示した遷移は各 \(k\) に対して根から探索することで \(\displaystyle O(|S_k|)\) で更新できます。

問題の答えは \(\displaystyle \min_{0\le i\le |S_k|} \left(|S_k|+d_{k-1}[S_{k}[:i]]-2i \right) \) ですが、 この値も \(d_{k-1}\) から \(d_k\) への更新と同じ要領で計算できます。

以上を適切に実装することでこの問題を解くことができます。

実装例 (Python3)

d = [0]
INF = 10**9
to = [[-1 for i in range(26)]]
for _ in range(int(input())):
    s = input()
    n = len(s)
    ans = n
    now = 0
    for i in range(1, n + 1):
        si = ord(s[i - 1]) - ord("a")
        if to[now][si] == -1:
            to[now][si] = len(to)
            to.append([-1 for _ in range(26)])
            d.append(INF)
        now = to[now][si]
        ans = min(ans, d[now] + n - 2 * i)
        d[now] = min(d[now], n)
    print(ans)

posted:
last update: