Official

E - Count ABC Again Editorial by sounansya


まず制約を無視すれば以下のような解法が考えられます:

  • 各クエリで \(S\)\(X_i\) 文字目を \(C_i\) に変更する。
  • \(S\) の長さ \(3\) の部分文字列の個数は \(N-2\) 個なので、それぞれに対して ABC と一致するかを判定し、一致する部分文字列の個数を出力する。

しかし、 \(N,Q\) は最大で \(2\times 10^5\) になるのでこの解法では TLE となってしまいます。

ここで、 \(S\) の一文字を変えても \(S\) の長さ \(3\) の部分文字列は高々 \(3\) 個しか変わらないことに着目します。

例えば \(S=\) ABCDEFGHI\(S=\) ABCZEFGI に変わったとします。すると、変更前の \(S\) の長さ \(3\) の部分文字列は

  • ABC, BCD, CDE, DEF, EFG, FGH, GHI

\(7\) 個ですが、変更後の \(S\) の長さ \(3\) の部分文字列は

  • ABC, BCZ, CZE, ZEF, EFG, FGH, GHI

\(7\) 個です。この例では変更前後で長さ \(3\) の部分文字列は \(3\) 個しか変わっていません。一般の場合でも長さ \(3\) の部分文字列は \(3\) 個以下しか変わりません。

よって、変わる \(3\) 個以下の部分文字列に対してのみ「変更前にいくつ ABC だったか」と「変更後にいくつ ABC か」を計算し、その差分と変更前の答えを元に変更後の答えを計算すれば良いです。計算量は \(O(N+Q)\) となります。

実装例(Python3)

N, Q = map(int, input().split())
S = list(input())
ans = 0
for i in range(N - 2):
    if S[i] == "A" and S[i + 1] == "B" and S[i + 2] == "C":
        ans += 1
for _ in range(Q):
    x, c = input().split()
    x = int(x) - 1
    for k in range(3):
        idx = x - k
        if 0 <= idx and idx + 2 < N:
            if S[idx] == "A" and S[idx + 1] == "B" and S[idx + 2] == "C":
                ans -= 1
    S[x] = c
    for k in range(3):
        idx = x - k
        if 0 <= idx and idx + 2 < N:
            if S[idx] == "A" and S[idx + 1] == "B" and S[idx + 2] == "C":
                ans += 1
    print(ans)

posted:
last update: