Official

A - Grandma's Footsteps Editorial by sheyasutaka


実装方針

走る速度は毎秒 \(S\) メートルで一定なので,走る秒数を求めてから \(S\) 倍すれば答えになります.

シミュレーション解法

開始時点の状態を「\(0\) 秒続けて走っている」,走った累計秒数を \(0\) で初期化し,\(1\) 秒ごとに状態を更新するシミュレーションを行うことで,走る累計秒数を数えることができます.

各更新では,以下のような処理を行います.

  • 今の状態が「走っている」なら,走った累計秒数を \(1\) 増やす.
  • 続けて走っている秒数を \(1\) 増やす.その後,以下の変更を行う.
    • 状態が「\(A\) 秒続けて走っている」なら「\(0\) 秒続けて止まっている」に変える.
    • 状態が「\(B\) 秒続けて止まっている」なら「\(0\) 秒続けて走っている」に変える.

より簡潔な解法

\(A+B\) 秒ごとに同じ動作を繰り返すので,\(X\) 秒間は \(\lfloor \frac{X}{A+B} \rfloor\) 回の反復と \(X \bmod (A+B)\) 秒のあまりに分割できます(\(\lfloor \frac{X}{A+B} \rfloor\)\(X \bmod (A+B)\) はそれぞれ,\(X\)\((A+B)\) で割った商とあまりを表す).

各反復は \(A\) 秒の走りと \(B\) 秒の静止からなるので,反復する部分では合計で \(A \times \lfloor \frac{X}{A+B} \rfloor\) 秒走ります.

あまりの部分を \(m\) 秒とおくと,このあいだにおける走る秒数は,以下のように場合分けして求めることができます.

  • \(m \leq A\) のとき,走る秒数は \(m\) 秒.
  • \(m > A\) のとき,走る秒数は \(A\) 秒.

以上の \(2\) つを足し合わせることで,\(X\) 秒全体における走る秒数が求まります.

実装例 (C++)

\(1\) 秒ごとにシミュレートする解法は以下のように書けます.

#include <iostream>
using std::cin;
using std::cout;
using std::min;


int main (void) {
	int s, a, b, x;
	cin >> s >> a >> b >> x;

	int len = 0;
	int mode = 0, cnt = 0; // mode 0: run, mode 1: stop
	for (int i = 0; i < x; i++) {
		if (mode == 0) len++;
		
		cnt++;
		if (mode == 0 && cnt == a) {
			mode = 1;
			cnt = 0;
		} else if (mode == 1 && cnt == b) {
			mode = 0;
			cnt = 0;
		}
	}

	int ans = len * s;
	cout << ans << "\n";

	return 0;
}

算数的に解く解法は以下のように書けます.

#include <iostream>
using std::cin;
using std::cout;
using std::min;


int main (void) {
	int s, a, b, x;
	cin >> s >> a >> b >> x;

	int len = 0;
	len += (x / (a+b)) * a; // repeats (a+b) seconds
	len += min(x % (a+b), a); // remainder

	int ans = len * s;
	cout << ans << "\n";

	return 0;
}

posted:
last update: