31歳の元保守運用エンジニアがAtCoder参加してみた 3回目

# はじめに
ABC335に参加したのでその振り返り。

https://atcoder.jp/contests/abc335

## A問
今回のA問は、単純だったが少し悩んだ。
というのもC++の関数について知識がなかったため。
回答内容は以下。
<details><summary>ソースコード</summary>

```A.cpp
#include<bits/stdc++.h>

using namespace std;

int main(void){
    string S;
    cin >> S;

    S.pop_back();

    cout << S << "4" << endl;

}
```
</details>

標準入力から**S**を受け取り、それの最後の文字を"4"に置き換える。
"2023"→"2024"でなく、文字通り末尾のみ変更すればよい。
末尾のみ削除する関数があったはず、という記憶があったのでググってみたところ
pop_back()関数についての記事を発見。

https://www.delftstack.com/ja/howto/cpp/remove-last-character-from-a-string-in-cpp/

15分ほどで提出し、AC(正解)。
公式解説にあったpush_back()関数については全く知らなかったため、上記のように出力の際に"4"を結び付けておくようにした。
C++についての知識が欠乏しているので、AtCoder公式が用意してくれている以下教材を学んでいきたいところ。

https://atcoder.jp/contests/APG4b

## B問
今回は比較的簡単だった。**本番で初めてB問が解けた。** やったね。
回答内容は以下。

<details><summary>ソースコード</summary>

```B.cpp
#include<bits/stdc++.h>

using namespace std;

int main(void){
    int N;
    cin >> N;

    for(int i = 0; i <= N; ++i){
        for(int j = 0; j <= N; ++j){
            for(int k = 0; k <= N; ++k){
                int l = i + j + k;
                if(l <= N){
                    cout << i << " " << j << " " << k << endl;
                }
            }
        }
    }
}

```
</details>

標準入力から**N**を受け取り、*x* + *y* + *z* ≦ N となるx, y, zを求める。
N ≦ 21、ということで3重ループにして計算させても、リソースへの負担は少量で済む。
つまり全探索でOK。
辞書的に小さい順で組み合わせを出力するのが条件なので、
zが最も内側の入れ子になるようにループを用意してあげればよい。
一番内側のループで変数**l**を宣言してやり、それがN以下であれば出力するように。
今回のB問はそこまで難しくなかった。
終わって気づいたが、for文内の各変数、x, y, zとそのまま設定した方が可読性が高かったと思う。

## C問
初のC問挑戦となった。
過去問でもまだC問は手を付けていなかったため、ぶっつけ本番。
結果から言うと、**時間内に回答できなかった。**
回答内容は以下。

:::note warn
警告
勿論ですが以下のコードを実行しても解けません！
:::

<details><summary>ソースコード</summary>

```C.cpp
#include<bits/stdc++.h>

using namespace std;

class Point
{
    public:
        int x;
        int y;

        Point() {}    // 初期化は何もしない

        Point(int x0, int y0)
        {
            x = x0;
            y = y0;
        }

        Point operator + (const Point& p0) const
        {
            Point p1;
            p1.x = x + p0.x;
            p1.y = y + p0.y;
            return p1;
        }

        void answer()
        {
            cout << x << " " << y << endl;
        }
};

int main(void){
    int N_numberOfParts;
    int Q_numberOfQuery;

    cin >> N_numberOfParts >> Q_numberOfQuery;

    vector<Point> positionOfParts(N_numberOfParts);
    for(int i = 1; i <= N_numberOfParts; ++i){
        Point p(i, 0);
        positionOfParts.push_back(p);
    }

    vector<vector<string>> query(Q_numberOfQuery, vector<string>(1));
    for (int i = 0; i < Q_numberOfQuery; ++i){
        cin >> query[Q_numberOfQuery][0] >> query[Q_numberOfQuery][1];
    }

    for(int i = 0; i < Q_numberOfQuery; ++i){
        if(query[i][0] == "1"){
            if(query[i][1] == "R"){
                for(int j = N_numberOfParts - 1; j >= 1; --j){
                    positionOfParts[j - 1] = positionOfParts[j];
                }
                Point q(1, 0);
                positionOfParts[0] = positionOfParts[0] + q;
            }else if(query[i][1] == "L"){
                for(int j = N_numberOfParts - 1; j >= 1; --j){
                    positionOfParts[j - 1] = positionOfParts[j];
                }
                Point q(-1, 0);
                positionOfParts[0] = positionOfParts[0] + q;
            }else if(query[i][1] == "U"){
                for(int j = N_numberOfParts - 1; j >= 1; --j){
                    positionOfParts[j - 1] = positionOfParts[j];
                }
                Point q(0, 1);
                positionOfParts[0] = positionOfParts[0] + q;
            }else if(query[i][1] == "D"){
                for(int j = N_numberOfParts - 1; j >= 1; --j){
                    positionOfParts[j - 1] = positionOfParts[j];
                }
                Point q(0, -1);
                positionOfParts[0] = positionOfParts[0] + q;
            }
        }
        else{
            int m = stoi(query[i][1]);
            positionOfParts[m].answer();
        }
    }

    return 0;
}
```
</details>

考え方として、Pointというクラスを作成し、各パーツの位置を座標点としてインスタンスで保持させようとした。
以下の記事が参考になった。

http://www.s-cradle.com/developer/sophiaframework/tutorial/Cpp/operator.html

あとはクエリの内容を判別し、頭をどの方向へ向かわせるかを決定。
そして残りのパーツの座標をひとつ前のパーツが持っていた情報に更新する……という流れ。
時間内に何とか間に合わせたかったが、時間切れ。

### 解説を見て
#### 2024/01/09追記

ただ、公式解説によると**deque**なる要素が用いられていた。
ここでもC++の知識がないことが足を引っ張った。
その理解は後回しにするとして、とりあえず自分なりの解法を完成させてみた。

<details><summary>ソースコード</summary>

```C_fixed.cpp
#include <iostream>
#include <vector>
using namespace std;

class Point {
public:
    int x;
    int y;

    Point() : x(0), y(0) {}

    Point(int x0, int y0) : x(x0), y(y0) {}

    Point operator+(const Point& p0) const {
        return Point(x + p0.x, y + p0.y);
    }

    void answer() {
        cout << x << " " << y << endl;
    }
};

int main() {
    int N_numberOfParts;
    int Q_numberOfQuery;

    cin >> N_numberOfParts >> Q_numberOfQuery;

    vector<Point> positionOfParts;
    for (int i = 0; i < N_numberOfParts; ++i) {
        Point p(i + 1, 0);
        positionOfParts.push_back(p);
    }

    vector<vector<string>> query(Q_numberOfQuery, vector<string>(2));
    for (int i = 0; i < Q_numberOfQuery; ++i) {
        cin >> query[i][0] >> query[i][1];
    }

    for (int i = 0; i < Q_numberOfQuery; ++i) {
        if (query[i][0] == "1") {
            if (query[i][1] == "R") {
                for (int j = N_numberOfParts - 1; j >= 1; --j) {
                    positionOfParts[j] = positionOfParts[j - 1];
                }
                Point q(1, 0);
                positionOfParts[0] = positionOfParts[0] + q;
            } else if (query[i][1] == "L") {
                for (int j = N_numberOfParts - 1; j >= 1; --j) {
                    positionOfParts[j] = positionOfParts[j - 1];
                }
                Point q(-1, 0);
                positionOfParts[0] = positionOfParts[0] + q;
            } else if (query[i][1] == "U") {
                for (int j = N_numberOfParts - 1; j >= 1; --j) {
                    positionOfParts[j] = positionOfParts[j - 1];
                }
                Point q(0, 1);
                positionOfParts[0] = positionOfParts[0] + q;
            } else if (query[i][1] == "D") {
                for (int j = N_numberOfParts - 1; j >= 1; --j) {
                    positionOfParts[j] = positionOfParts[j - 1];
                }
                Point q(0, -1);
                positionOfParts[0] = positionOfParts[0] + q;
            }
        } else {
            int m = stoi(query[i][1]);
            positionOfParts[m - 1].answer();
        }
    }

    return 0;
}
```
</details>

入力例と共に実行してみると、正しい出力例が出た！
やったねと思って提出してみると、残念ながら一部の回答で**TLE(実行時間制限超過)**。
恐らく各パーツごとにインスタンスを生成してしまっているから、
問題によってはメモリを食ってしまっている模様。
ACになっている回答もあり、それは実行時間・メモリ共に負荷が低かったため、そのように想定。
最近はC問からアルゴリズムを活用しないと解けない、と耳にしたので、
その洗礼を受けた形だった。
ともかく自分なりのupsolveはできた。

# 振り返り
今回のABCでは、初めて試験時間ずっとエディタとにらめっこしていた。
これまで大抵、問題が解けなくなったことで気分転換に家事など挟んでいた。
それが今回はずっとコーディングに向かい合うことができた。
少し進歩したかもしれない。