けんちょんの競プロ精進記録

競プロの精進記録や小ネタを書いていきます

AtCoder ABC 342 C - Many Replacement (3Q, 茶色, 350 点)

これ実は「アルファベット文字の変換テーブルを愚直に作る」という素朴な方法が解けるけど、意外と盲点になりそうだ!

問題概要

英小文字のみからなる長さ  N の文字列  S が与えられる。次の  Q 回の操作を実行後の文字列を出力せよ。

【操作】
文字  c, d が与えられるので、文字列  S 中の文字  c をすべて文字  d に置き換える

制約

  •  1 \le N, Q \le 2 \times 10^{5}

考えたこと

これ一瞬、高度なデータ構造が必要に思えるのだけど、注目すべきことはたった 1 つ。


英小文字は 26 種類しかない


というところだ。文字列  S の長さがたとえ  10^{5} などあったとしても、同じ文字に対する最終結果は同じなのだから、高々 26 箇所だけ考えれば良いのだ!!!

具体的には、次のような配列を求めよう。


  • convert[c]:文字  c が操作によってどの文字に変わるか

そして、 Q 回のクエリでこの値を順次更新していく。具体的には、クエリ  (c, d) に対しては

  • convert[x] == c であるようなすべての  x に対して
  • convert[x] = d と更新する

というようにすればよい。

計算量は、英小文字の種類数を  \sigma として、 O(N + Q\sigma) と評価できる。

コード

#include <bits/stdc++.h>
using namespace std;

int main() {
    int N, Q;
    char c, d;
    string S;
    cin >> N >> S >> Q;

    vector<int> convert(26);
    for (int i = 0; i < 26; i++) convert[i] = i;
    while (Q--) {
        cin >> c >> d;
        c -= 'a', d -= 'a';

        // 文字 c を文字 d に書き換える
        for (int i = 0; i < 26; i++) {
            if (convert[i] == c) convert[i] = d;
        }
    }

    // もとの文字列を書き換える
    for (auto &c : S) c = (char)(convert[c - 'a'] + 'a');
    cout << S << endl;
}