今回は paiza の「ポスターの貼り付け作業」の問題に挑戦!
🧩 問題概要
- 池の周りに
N本の木 があり、木は時計回りに 1〜N 番 で番号が付いている。 - 最初に 木
Aにポスターを貼り付ける。 - その後は次のルールに従って、すべての木にポスターを貼る順番を求める。
🔹 貼り付けルール
- 方向
Sが"CW"なら時計回り、"CCW"なら反時計回りに進む。 - ポスターを貼っていない木だけを数えて、
B本目の木に次のポスターを貼る。 - すべての木にポスターを貼るまでこれを繰り返す。
- 途中で同じ木に戻ってきても、「貼っていない木」だけをカウントする
🔹 入出力形式
入力
N ← 木の本数
A ← 最初に貼る木の番号(1始まり)
S ← "CW" or "CCW"(進行方向)
B ← 数える間隔(B 本目に貼る)
出力
ポスターを貼った順番(半角スペース区切り)
入力例:
5
2
CW
3
出力例:
2 5 4 1 3
✅OK例:
// readline モジュールを使って標準入力を受け取る準備
const rl = require('readline').createInterface({ input: process.stdin });
// 入力行を格納する配列
const lines = [];
// 入力を1行ずつ配列に追加
rl.on('line', (input) => lines.push(input));
// 入力終了後に処理を実行
rl.on('close', () => {
// 入力データの読み取り
const N = Number(lines[0]); // 木の本数
const A = Number(lines[1]); // 最初にポスターを貼る木の番号(1始まり)
const S = lines[2]; // 進行方向("CW" or "CCW")
const B = Number(lines[3]); // 進む間隔
// 木の番号リスト(0からN-1までの配列)
let trees = Array.from({ length: N }, (_, i) => i);
// 貼った順番を格納する配列
const ans = [];
// 現在位置(配列のインデックス)※0始まりに調整
let cur = A - 1;
// 全ての木にポスターを貼るまで繰り返す
while (trees.length > 0) {
// 現在の木にポスターを貼る(出力用に+1して元の番号に戻す)
ans.push(trees[cur] + 1);
// 現在の木を削除(もう貼らない)
trees.splice(cur, 1);
// 全て貼り終えたら終了
if (trees.length === 0) break;
// 次の位置を計算
if (S === 'CW') {
// 時計回り:B-1本進む
cur = (cur + B - 1) % trees.length;
} else if (S === 'CCW') {
// 反時計回り:B本戻る(負の値防止に+trees.length)
cur = (cur - B + trees.length) % trees.length;
}
// 念のため負インデックス補正(範囲を0〜length-1に保つ)
cur = (cur + trees.length) % trees.length;
}
// 結果をスペース区切りで出力
console.log(ans.join(' '));
});
🧭 コードの流れ
- 入力準備
-
readlineモジュールで標準入力(コンソール入力)を受け取る準備をする。 - 入力された各行を
lines配列に保存。
-
- 入力終了後の処理 (rl.on('close', ...))
- 入力内容をそれぞれの変数に変換して使いやすくする。
-
N: 木の本数 -
A: 最初にポスターを貼る木(1始まり) -
S: 進行方向(CW: 時計回り /CCW: 反時計回り) -
B: 進む間隔(B本目の木に貼る)
-
- 入力内容をそれぞれの変数に変換して使いやすくする。
- 木のリストを作成
-
trees = [0, 1, 2, ..., N-1]
→ まだポスターを貼っていない木の番号を管理するための配列。
-
- 現在位置を設定
-
cur = A - 1
→ 入力が1始まりなので、配列インデックス(0始まり)に合わせて調整。
-
- 繰り返し処理開始
-
trees配列が空になるまで繰り返す。
-
- 現在の木にポスターを貼る
-
ans.push(trees[cur] + 1)
→ 木の番号を出力用に1始まりに戻して保存。 -
trees.splice(cur, 1)
→ 貼った木をリストから削除(もう選ばれない)。
-
- 全て貼り終えたら終了
if (trees.length === 0) break;
- 次に貼る木を決定
- 時計回り(
CW)の場合:
→cur = (cur + B - 1) % trees.length
現在の木を除外して、右方向にB本進む。 - 反時計回り(
CCW)の場合:
→cur = (cur - B + trees.length) % trees.length
左方向にB本戻る(負のインデックス防止で補正)。
- 時計回り(
- 負インデックスの補正
-
cur = (cur + trees.length) % trees.length
→ 配列の範囲外にならないように調整。
-
- 結果出力
- 全ての木に貼った順番を
console.log(ans.join(' '))で表示。
- 全ての木に貼った順番を
📝 学習のまとめ
考え方:
「貼っていない木」だけが残るリストから、
現在位置を基準にB本目を数えて削除していくシミュレーション。
🪄 ポイント:
- 配列の削除 (
splice) → 貼り終えた木をリストから除外。 - インデックスの補正 (
% trees.length) → 配列の端を超えたらループ。 - 方向ごとに移動式が異なる
- 時計回り:
+B-1 - 反時計回り:
-B
- 時計回り:
- 常に「貼っていない木」だけをカウントするのがキーポイント。