アルゴリズム概要

n 個のボール [0, 1, 2, …, n-1] が並んでいる。 以下の操作をステップ i = 0, 1, …, n-1 の順に実施する: 配列[i : n] を in-place で逆順にする

最終的にボール番号 k が何番目のインデックスにあるかを答える。 シミュレーションすると最終配列には明確なパターンがあり、閾値 τ = ⌊n/2⌋ を使って O(1) で答えられる。

入出力例

入力:
2
3 1   ← n=3, k=1
5 2   ← n=5, k=2

出力:
2
4

数式(閾値分岐)

τ = ⌊n / 2⌋
k < τ → index = 2·k + 1(奇数位置)
k ≥ τ → index = 2·(n−1−k)(偶数位置)

最終配列のパターン(n=6 の例)

インデックス 0 1 2 3 4 5
値(ボール番号) 5 0 4 1 3 2
グループ 偶数 奇数 偶数 奇数 偶数 奇数

偶数インデックスに大きいボール番号、奇数インデックスに小さいボール番号が交互配置される。

ステップバイステップ解説

Python 実装

HackerRank 形式・型注釈付き。競技用と業務用の2パターンを掲載。

from __future__ import annotations
import sys
from typing import Final

input = sys.stdin.readline


def solve_competitive(n: int, k: int) -> int:
    """
    競技プログラミング向け実装(性能最優先)

    最終配列パターン:
      偶数インデックス: n-1, n-2, n-3, ...
      奇数インデックス: 0, 1, 2, ...

    閾値 tau = n // 2 で分岐:
      k <  tau  →  奇数位置  →  2*k + 1
      k >= tau  →  偶数位置  →  2*(n-1-k)

    Time : O(1)
    Space: O(1)
    """
    tau: Final[int] = n >> 1          # n // 2(ビットシフト)
    if k < tau:
        return (k << 1) | 1           # 2*k + 1
    return (n - 1 - k) << 1           # 2*(n-1-k)


def solve_production(n: int, k: int) -> int:
    """
    業務開発向け実装(型安全・エラーハンドリング重視)

    Args:
        n: ボールの総数 (n >= 1)
        k: 検索するボール番号 (0 <= k < n)
    Returns:
        ボール k の最終インデックス (0-based)
    Raises:
        ValueError: n または k が制約を満たさない場合
    """
    if n < 1:
        raise ValueError(f"n must be >= 1, got {n}")
    if not (0 <= k < n):
        raise ValueError(f"k must satisfy 0 <= k < n, got k={k}, n={n}")

    tau: Final[int] = n // 2

    # k < tau  →  奇数インデックスに配置  →  2*k + 1
    if k < tau:
        return 2 * k + 1

    # k >= tau  →  偶数インデックスに配置  →  2*(n-1-k)
    return 2 * (n - 1 - k)


if __name__ == "__main__":
    t: int = int(input().strip())
    for _ in range(t):
        parts = input().rstrip().split()
        n_val: int = int(parts[0])
        k_val: int = int(parts[1])
        print(solve_competitive(n_val, k_val))

フローチャート

開始: n, k を受け取る τ = ⌊n / 2⌋ 閾値を計算 k < τ ? はい 奇数インデックス 2·k + 1 いいえ 偶数インデックス 2·(n−1−k) インデックスを出力 print(result) 終了 次のテストケース (t 回繰り返す)

フローの説明:
1. nk を受け取り、閾値 τ = ⌊n/2⌋ を計算する。
2. k < τ なら奇数インデックス側 → 2·k + 1 を返す。
3. k ≥ τ なら偶数インデックス側 → 2·(n−1−k) を返す。
4. テストケース数 t 回だけループする(紫の破線)。

計算量分析

アプローチ 時間計算量 空間計算量 備考
✅ 本手法(数式導出) O(1) O(1) 閾値判定と算術演算のみ。採用。
ナイーブ シミュレーション O(n²) O(n) n 回の逆順各 O(n)。大きい n でTLE。
部分観察(1ステップ記録) O(n) O(n) シミュレーションを1回に削減可能だが不要。

CPython 最適化ポイント

  • n >> 1 … n // 2(ビットシフト)
  • k << 1 … 2 * k(ビットシフト)
  • (k << 1) | 1 … 2*k + 1(ビット演算)
  • sys.stdin.readline … I/O 3倍高速化

エッジケース一覧

  • n=1, k=0 → τ=0, k≥τ → 2(1-1-0)=0 ✓
  • n=2, k=0 → τ=1, k<τ → 2(0)+1=1 ✓
  • n=2, k=1 → τ=1, k≥τ → 2(2-1-1)=0 ✓
  • n=3, k=1 → τ=1, k≥τ → 2(3-1-1)=2 ✓
  • n=5, k=2 → τ=2, k≥τ → 2(5-1-2)=4 ✓