AtCoder Beginner Contest 342 振り返り

# ABC342
## 概要
https://atcoder.jp/contests/abc342

## A - Yay!
__考えてたこと__
結構悩んだ。あまり良い解法が思いつかなくて1文字目と他の文字を比較して一つだけ違うものがあればそれを出力、無ければ1文字目という感じで強引に解決。

__提出したもの__
```c++:a.cpp
int main() {
    string s;
    cin >> s;
    char first = s[0];
    int ans;
    int cnt = 0;
    for (int i = 0; i < s.size(); i++) {
        if (first != s[i]) {
            ans = i + 1;
            cnt++;
        }
    }
    if (cnt > 1) {
        ans = 1;
    }
    cout << ans << endl;
    return 0;
}
```

__振り返り__
解答見たら二重for文で片方の文字を固定して全ての文字と比較するという方法でした。綺麗なやり方で好き。

## B - Which is ahead?
__考えてたこと__
i番目の人がPiというのをmapに保存して後は比較して終わり。
頭の中で整理するのにちょっと時間がかかったけど、最近似たようなmapを使うd問題を解いてたから解けた感じ。

__提出したもの__
```c++:b.cpp
int main() {
    int n;
    cin >> n;

    map<int, int> map;
    for (int i = 0; i < n; i++) {
        int num;
        cin >> num;
        map[num] = i;
    }
    int q;
    cin >> q;
    rep(i, 0, q) {
        int a, b;
        cin >> a >> b;
        if (map[a] > map[b]) {
            cout << b << endl;
        } else
            cout << a << endl;
    }
    return 0;
}
```
__振り返り__
慣れなのかもしれないけど、こういう項目が複数ある問題頭がごちゃごちゃになっちゃうからもっと早く解けるようになりたい。

## C - Many Replacement
__考えてたこと__
全ての文字を毎回変換したら計算量がN*Qで4*10**10でTLEになるので何かしら工夫をする必要があると判断。
サンプルケースみたり少ない文字で考えてみて、この文字はこの文字になる、みたいな情報だけ保持して最後にまとめて判断すれば良いんじゃないか...?と考えて実装したらAC。

__提出したもの__
```c++:c.cpp
int main() {
    int n, q;
    string s;
    cin >> n >> s >> q;

    map<char, char> map;
    rep(i, 0, q) {
        char a, b;
        cin >> a >> b;
        if (!(map.count(a))) {
            map[a] = b;
        }
        fore(x, map) {
            if (x.second == a) {
                x.second = b;
            }
        }
    }
    fore(a, s) {
        if (map.count(a)) {
            cout << map[a];
        } else
            cout << a;
    }
    return 0;
}
```

__振り返り__
コードはかなり違うけどやってること自体は模範解答と大体同じそう。最近C問題に関しては全探索した時の計算量がいくらかっていう点から工夫して解く必要があるかどうかということを考えるようになったの良い傾向な気がする。

## D - Square Pair
__考えてたこと__
かなり悩んだ問題。まず計算量を考えて全パターンを試したらN*(N-1)/2で計算量が足りないと考えて何かしら工夫する必要があると判断。とはいえ、最初はどうやって平方数か判断するかも分からずかなり迷走。
小さい数で色々試した結果、全ての値を割り切れる最大の平方数で割って同じ値のものを組み合わせたら解になると気づいてその方針で実装。
(例えば12の場合2*2*3なので3とする。同じ処理をして3になる、3や108(2*2*3*3*3)などと組み合わせた時平方数になる。)

__提出したもの__
```c++:d.cpp
int main() {
    ll n;
    cin >> n;
    // ここのmapを<int,int>にしてるとWAになる。
    // 下のmap.second*(map.second-1)のところでintの範囲超えそう
    // map.secondの最大値がnのため、n**2で4*10**10になる。
    map<int, ll> map;
    for (ll i = 0; i < n; i++) {
        ll a;
        cin >> a;
        if (a != 0) {
            for (int i = sqrt(200000) + 1; i > 0; i--) {
                if (a % (i * i) == 0) {
                    a /= (i * i);
                }
            }
        }

        if (map.count(a)) {
            map[a]++;
        } else {
            map[a] = 1;
        }
    }

    ll ans = 0;
    fore(a, map) {
        if (a.first == 0) {
            for (ll i = 1; i <= a.second; i++) {
                ans += n - i;
            }
        } else {
            ans += a.second * (a.second - 1) / 2;
        }
    }
    cout << ans << endl;
    return 0;
}
```
__振り返り__
方針自体は合っていたが数値が0の時の処理、intの範囲を超えるケースがあること、などで実装が手間取り最終的に7WAからのAC。
方針を思いつけたのは良かったが0の時など例外の値の処理は気を付けていきたい。int, long longに関してはもっと初歩的なことだし二乗の計算をする時はそれがintの範囲内で収まるか考える癖をつける必要がある。

## 感想
最近、自力でD問題まで解けることが多くて嬉しい。多分、コンテスト参加じゃなくてゆっくり落ち着いて時間をかけられてるからだと思うけど。あとはこれをコンテストでも出せるぐらい実践値を上げていきたい。