公式
C - 観覧車の眺め / View from the Ferris Wheel 解説 by admin
Claude 4.6 Opus (Thinking)概要
円形に並んだ \(N\) 個のゴンドラから連続する \(M\) 個を選び、美しさの合計を最大化する問題です。スライディングウィンドウを用いて効率的に解きます。
考察
問題の整理
ゴンドラは円形に並んでいるため、例えば \(N=5, M=3\) のとき、選べる区間は以下の \(5\) 通りです:
- \([A_1, A_2, A_3]\)
- \([A_2, A_3, A_4]\)
- \([A_3, A_4, A_5]\)
- \([A_4, A_5, A_1]\)(端をまたぐ)
- \([A_5, A_1, A_2]\)(端をまたぐ)
すべての区間について合計を求め、その最大値を出力すればよいです。
素朴なアプローチの問題点
各開始位置 \(i\)(\(N\) 通り)に対して、\(M\) 個の要素を毎回足し合わせると、計算量は \(O(N \times M)\) になります。\(N\) が最大 \(5 \times 10^5\) のとき、最悪 \(O(N^2)\) 程度になり、TLE(時間超過)の恐れがあります。
解決策:スライディングウィンドウ
ウィンドウ(区間)を1つずらすとき、新しく入る要素を足し、出ていく要素を引くだけで、次の区間の合計が \(O(1)\) で求まります。これを利用すれば全体を \(O(N)\) で処理できます。
アルゴリズム
- 最初の区間 \([A_1, A_2, \ldots, A_M]\) の合計を計算し、
current_sumとする。 max_sum = current_sumで初期化する。- 開始位置 \(i\) を \(1\) から \(N-1\) まで動かしながら、以下を繰り返す:
- 新しく入る要素: \(A_{(i + M - 1) \bmod N}\) を
current_sumに加える。 - 出ていく要素: \(A_{i-1}\) を
current_sumから引く。 max_sumを更新する。
- 新しく入る要素: \(A_{(i + M - 1) \bmod N}\) を
- 最終的な
max_sumを出力する。
具体例
\(N=5, M=3, A=[2, -1, 4, 5, 3]\) の場合:
| 開始位置 \(i\) | 区間 | 加える要素 | 引く要素 | current_sum |
|---|---|---|---|---|
| 0 | \([2, -1, 4]\) | — | — | \(5\) |
| 1 | \([-1, 4, 5]\) | \(A_3=5\) | \(A_0=2\) | \(8\) |
| 2 | \([4, 5, 3]\) | \(A_4=3\) | \(A_1=-1\) | \(12\) |
| 3 | \([5, 3, 2]\) | \(A_0=2\) | \(A_2=4\) | \(10\) |
| 4 | \([3, 2, -1]\) | \(A_1=-1\) | \(A_3=5\) | \(4\) |
最大値は \(12\) です。
計算量
- 時間計算量: \(O(N)\) — 初期区間の合計に \(O(M)\)、その後のスライドに \(O(N)\)。合わせて \(O(N)\)。
- 空間計算量: \(O(N)\) — 配列 \(A\) の格納に必要。
実装のポイント
円形配列の処理: 配列を2つ連結する方法もありますが、インデックスに \(\bmod N\) を使うことでメモリを節約しつつ円形を扱えます。コード中の
A[(i + M - 1) % N]がこれに該当します。高速な入力: \(N\) が大きいため、
sys.stdin.buffer.read()を使って入力を一括で読み込み、高速化しています。ソースコード
import sys
def main():
input_data = sys.stdin.buffer.read().split()
N = int(input_data[0])
M = int(input_data[1])
A = [int(input_data[i + 2]) for i in range(N)]
# Circular: extend the array
# Compute sliding window sum of size M over circular array
# We can concatenate A with itself and take sliding window
current_sum = sum(A[:M])
max_sum = current_sum
for i in range(1, N):
current_sum += A[(i + M - 1) % N] - A[i - 1]
if current_sum > max_sum:
max_sum = current_sum
print(max_sum)
main()
この解説は claude4.6opus-thinking によって生成されました。