Official

B - 廊下を往復するロボット / Robot Going Back and Forth in a Hallway Editorial by MMNMM


廊下の両端に鏡を置いて、反射した鏡の向こうの廊下も含めた数直線全体に対応する無限の長さの廊下について考えます。

すると、廊下の端でロボットが反射する動きは、鏡の向こうからやってきたロボットと入れ替わる動きだと思うことができます。 つまり、ロボット(元あったロボットおよび鏡の中の無限個のロボット)はすべて等速直線運動をしていると考えることができます。

現実の廊下に目盛りを書いておくことを考えると、鏡の中の無限の長さの廊下は、この目盛りとそれを反転させたものを一周期とする周期 \(2L\) の目盛りが書かれていることがわかります。

よって、\(X _ i+V _ i\times T\bmod{2L}\) の値がわかればこの問題を解くことができます。 具体的には、\(X _ i+V _ i\times T\) を \(2L\) で割った余りを \(m _ i\) とすると、答えは \(m _ i\le L\) なら \(m _ i\) 、そうでなければ \(2L-m _ i\) となります。

実装例は以下のようになります。

#include <iostream>
using namespace std;

int main() {
    int N, L, T;
    cin >> N >> L >> T;

    for (int i = 0; i < N; ++i) {
        int X, V;
        cin >> X >> V;

        long free_move = X + static_cast<long>(V) * T; // 無限の廊下を等速直線運動
        long modulo = (2 * L + free_move % (2 * L)) % (2 * L); // 周期 2L の中に入れて
        cout << min(modulo, 2 * L - modulo) << endl; // 前半か後半かで場合分け
    }
    return 0;
}
N, L, T = map(int, input().split())

for i in range(N):
    X, V = map(int, input().split())
    free_move = X + V * T # 無限の廊下を等速直線運動
    modulo = free_move % (2 * L) # 周期 2L の中に入れて
    print(min(modulo, 2 * L - modulo)) # 前半か後半かで場合分け

posted:
last update: