개념

연속한 일정 길이 구간의 정보를 유지하면서 구간을 한 칸씩 이동하는 방법입니다. 각 구간의 합을 처음부터 다시 구하는 대신 빠진 원소를 빼고 새 원소를 더합니다.

고정 길이 구간

길이 KK인 첫 구간의 합을 구합니다. 오른쪽으로 한 칸 옮기면 왼쪽 끝의 값 하나가 빠지고 오른쪽에 값 하나가 들어옵니다.

[2,1,4,3,5][2,1,4,3,5]에서 길이 33인 구간 합은 7,8,127,8,12입니다. 첫 합 77에서 22를 빼고 33을 더하면 다음 합 88을 얻습니다.

첫 구간과 다음 구간의 합은 각각 2+1+42+1+4와 1+4+31+4+3입니다. 가운데 1+41+4가 겹치므로 다시 더하는 대신 빠진 22를 빼고 들어온 33을 더할 수 있습니다. 매번 길이 KK의 합을 처음부터 구하면 구간마다 KK번 더하지만, 이 방법은 다음 구간으로 옮길 때 두 값만 처리합니다.

같은 길이의 모든 연속 구간을 순서대로 확인할 때 적합합니다. 길이가 서로 다른 임의의 구간 합을 여러 번 묻는다면 누적 합으로 각 구간을 바로 계산하는 방법을 사용할 수 있습니다.

복잡도

원소 수를 NN, 구간 길이를 KK라고 합니다. 첫 구간을 계산한 뒤에는 원소 하나를 빼고 하나를 더해 갱신합니다.

연산시간복잡도공간복잡도
첫 구간 합 계산O(K)O(K)추가 O(1)O(1)
전체 구간 확인O(N)O(N)입력 O(N)O(N), 추가 O(1)O(1)

예제

문제

길이가 KK인 연속 구간 중 합이 가장 큰 구간의 합을 구하여라.

입력

첫째 줄에 원소 수 NN과 구간 길이 KK가 공백을 사이에 두고 주어진다. 1≤K≤N≤1 0001\le K\le N\le1\,000이다.

둘째 줄에 수열의 원소 a1,a2,…,aNa_1,a_2,\ldots,a_N이 공백을 사이에 두고 주어진다. 1≤ai<10 0001\le a_i<10\,000이다.

출력

구간 합의 최댓값을 출력한다.

예제 입력

5 3
2 1 4 3 5

예제 출력

12

예제 코드

C++20

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

vector<int> v;

int main() {
    int n, k, i, s, ans;

    cin >> n >> k;
    v.resize(n);
    for (i = 0; i < n; ++i) {
        cin >> v[i];
    }
    s = 0;
    for (i = 0; i < k; ++i) {
        s += v[i];
    }
    ans = s;
    for (i = k; i < n; ++i) {
        s -= v[i - k];
        s += v[i];
        ans = max(ans, s);
    }
    cout << ans << '\n';
}