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

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

AtCoder ABC 369 B - Piano 3 (6Q, 灰色, 200 点)

このようなシミュレーションをサッと書けるようになりたいところ!

問題概要

横一列に 100 個の鍵盤からなるピアノがある。各鍵盤には順に  1, 2, \dots, 100 と番号が振られている。

鍵盤を  N 回押す。 i 回目の鍵盤の位置は  A_{i} であり、 S_{i} = 'L' のとき左手で押し、 S_{i} = 'R' のとき右手で押す。

演奏開始時には、左手と右手を好きな位置に配置できる。その後は、

  • 左手を鍵盤  x から鍵盤  y へ移動するとき:疲労度が  |x - y| 増加する
  • 右手を鍵盤  x から鍵盤  y へ移動するとき:疲労度が  |x - y| 増加する

演奏終了時の疲労度の最小値を求めよ。

制約

  •  1 \le N \le 100
  •  1 \le A_{i} \le 100

考えたこと

疲労度の最小値を求めたいという話であるが、結局のところ

  • 2 回目以降の左手使用のときは、その位置と、前回の左手の位置との差分を足す
  • 2 回目以降の右手使用のときは、その位置と、前回の右手の位置との差分を足す

というようにしていけばよい。この処理をシミュレーションしていくためには、次のような値を管理する必要がある。


  • prev_L:直近で左手で押した鍵盤の位置(まだ押していないときは -1)
  • prev_R:直近で右手で押した鍵盤の位置(まだ押していないときは -1)

これらの値を更新しながらシミュレーションしていこう。

コード

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

int main() {
    int N;
    cin >> N;
    vector<int> A(N);
    vector<char> S(N);
    for (int i = 0; i < N; i++) cin >> A[i] >> S[i];

    int res = 0, prev_L = -1, prev_R = -1;
    for (int i = 0; i < N; i++) {
        if (S[i] == 'L') {
            if (prev_L != -1) {
                // 前回の L の位置との差分を足す
                res += abs(A[i] - prev_L);
            }
            // 最後の L の位置を更新する
            prev_L = A[i];
        } else {
            if (prev_R != -1) {
                // 前回の R の位置との差分を足す
                res += abs(A[i] - prev_R);
            }
            // 最後の R の位置を更新する
            prev_R = A[i];
        }
    }
    cout << res << endl;
}