累積和の練習でAOJ Maximum Sum を解く

累積和の練習で、Aizu Online JudgeのMaximum Sumを解いて解説します。

https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0516

n個の整数からなる数列と整数kが与えられ、
連続して並ぶk個の整数の和の最大値を求める問題です。

nは 1 \leq n \leq 10^5で、kは 1 \leq k \leq nです。
単純に頭からk個の整数を読み取りながら足していくと、
n - k 箇所でk回の足し算が必要になり、計算量は O(n-k * k)になり、アウトです。
そこで、累積和の考え方でk回の足し算をしないように工夫します。

accを累積和を格納する配列とした時に、acc[i]をインデックス0からiまでの累積和になるようにします。

acc[0] = a_arr[0]
for i in range(1, n):
    acc[i] = acc[i - 1] + a_arr[i]

この累積和の配列を使って、インデックスiから i + kまでの和は以下の通りです。

acc[i + k] - acc[i]

連続して並ぶk個の整数の和の最大値を求めたいので、以下のようにします。

ans = max(ans, acc[j + k] - acc[j])

最後のコードは以下の通りです。

def solve(n: int, k: int, a_arr: list) -> int:
    acc = [0 for _ in range(n)]
    acc[0] = a_arr[0]
    for i in range(1, n):
        acc[i] = acc[i - 1] + a_arr[i]

    j = 0
    ans = 0
    while j + k < n:
        ans = max(ans, acc[j + k] - acc[j])
        j += 1
    return ans


while True:
    n, k = map(int, input().split())
    if n == 0 and k == 0:
        exit()
    a_arr = [int(input()) for _ in range(n)]
    print(solve(n, k, a_arr))

2日連続で簡単な累積和の問題を解きました。
次はもう少し難しめの累積和の問題にトライしようと思います。