누적 합

누적 합

저자 Егор Горбачев
편집 Сергей Слотин
게시 2021
정의. 배열 $[a_0, a_1, a_2, \ldots, a_{n - 1}]$의 누적 합이란 다음과 같이 정의되는 배열 $[s_0, s_1, s_2, \ldots, s_n]$을 말합니다: $$ \begin{aligned} & s_0 = 0\\ & s_1 = a_0\\ & s_2 = a_0 + a_1\\ & s_3 = a_0 + a_1 + a_2\\ & \ldots\\ & s_n = a_0 + a_1 + \ldots + a_{n - 1} \end{aligned} $$

이러한 인덱싱에서는 다음 사항에 유의하십시오

  • $s_k$는 $a_k$를 포함하지 않는 배열 $a$의 처음 $k$개 원소의 합과 같으며,
  • $s$의 길이는 $a$의 길이보다 1만큼 깁니다,
  • $s_0$은 항상 0입니다.

때로는 누적 합을 오른쪽 끝을 포함하고 0번째 원소 없이, 즉 $s_k = a_0 + a_1 + \ldots + a_k$로 정의하기도 합니다. 하지만 닫힌 구간이 반열린 구간보다 거의 항상 덜 편리한 것과 같은 이유로, 우리는 항상 정의에 따른 ‘반열린 구간’ 방식의 누적 합을 사용하겠습니다.

$s_k$에 대한 공식은 $s_{k+1} = s_k + a_k$와 같이 점화식으로 쓸 수 있으며, 이로부터 누적 합을 선형 시간에 계산하는 방법을 곧바로 얻을 수 있습니다.

int s[n + 1];

s[0] = 0;

for (int i = 0; i < n; i++)
    s[i + 1] = s[i] + a[i];

문제. 정수 배열이 주어지고, 「위치 $l$부터 위치 $r$까지의 반구간에서 합을 구하라」 형태의 쿼리가 들어옵니다. 쿼리에 $O(1)$에 답해야 합니다.

쿼리에 답하기 전에 원래 배열에 대한 누적 합 배열을 미리 계산해 둡시다. 그러면 모든 쿼리에서 $l$이 0이라면, 쿼리의 답은 단순히 누적 합 $s_r$일 것입니다. 그런데 $l \neq 0$이라면 어떻게 해야 합니까?

누적 합 $s_r$에는 우리에게 필요한 모든 원소가 들어 있지만, 불필요한 원소들도 함께 들어 있습니다. 바로 $a_0, a_1, \ldots, a_{l - 1}$입니다. 이러한 합은 다시 이미 계산해 둔 누적 합 $s_l$과 같다는 점에 주목하십시오. 따라서 다음 항등식이 성립합니다.

$$ a_{l} + a_{l + 1} + \ldots + a_{r - 1} = s_{r} - s_{l} $$

임의의 반구간에서 합을 구하는 쿼리에 답하려면 미리 계산해 둔 두 누적 합의 차를 구하기만 하면 됩니다.

#기타 연산

이와 같은 기법은 덧셈뿐만 아니라 다른 연산에도 사용할 수 있습니다.

여기서 우리가 덧셈에 실제로 필요로 했던 것은 무엇입니까? 덧셈에 역연산인 뺄셈이 있다는 점뿐입니다. 뺄셈을 이용하면 $s_l$을 “취소"하여 두 접두사로부터 구간의 값을 복원할 수 있습니다. 합은 역연산이 가능하지만, 예를 들어 최솟값이나 최댓값은 역연산이 불가능합니다. 일반적인 경우 접두사의 최솟값들로부터 구간의 최솟값을 구하는 것은 불가능합니다(배열의 첫 번째 원소가 최솟값인 경우를 생각해 보면 쉽게 확인할 수 있습니다. 이때 모든 누적 합은 그 원소와 같아지므로 나머지 값들에 대한 모든 의존성이 사라집니다).

덧셈 외에도 역연산이 가능한 연산이 있습니다:

  • 비트 단위 배타적 「논리합」, 즉 xor로도 알려져 있으며 $\oplus$로 표기하는 연산,
  • 모듈러 덧셈,
  • 곱셈과 모듈러 곱셈(역연산은 나눗셈).

일반적인 합 외에 가장 많이 쓰이는 것은 xor이며, 이는 훨씬 더 간단하게 계산됩니다:

$$ a_l \oplus a_{l + 1} \oplus \ldots \oplus a_{r - 1} = s_r \oplus s_l $$

#누적 합 문제

문제. 정수 배열이 주어집니다. 이 배열에 주어진 합을 갖는 부분 구간이 있는지 선형 시간에 판별하십시오.

문제. 길이가 같은 두 배열이 주어집니다. (해당 구간의 인덱스에서) 첫 번째 배열의 원소 합과 두 번째 배열의 원소 합이 같아지는 부분 구간을 찾으십시오.

문제. $n$개의 정수로 이루어진 멀티셋이 주어집니다. 원소의 합이 $n$으로 나누어떨어지는 부분집합을 아무거나 하나 찾으십시오.