[알고리즘] 코테 유형 분석 11. 누적합(구간 합)

최민길(Gale)·2023년 8월 7일
2

알고리즘

목록 보기
107/172

안녕하세요 이번 시간에는 누적합 문제의 유형을 분석해보도록 하겠습니다.

누적합은 합 배열을 이용하여 시간 복잡도를 줄여야 하는 문제에서 사용됩니다. 1차원 누적합의 경우 S[i] = S[i-1] + A[i]로 정의할 수 있으며 i에서 j까지의 합은 S[j] - S[i-1]과 같이 정의할 수 있습니다. 2차원 누적합의 경우 0,0 부터 i,j까지의 사각형 영역 안에 있는 수의 합으로 정의하며 S[i][j] = S[i][j-1] + S[i-1][j] - S[i-1][j-1] + A[i][j]로 정의됩니다. 여기서 중요한 점은 사각형 영역 안이기 때문에 구간 합을 구하는 방식이 다르다는 점입니다. i1,j1에서 i2,j2까지의 합의 경우 i2,j2까지의 합에서 i1-1,j2와 i2,j1-1을 빼준 후 중복해서 빠진 i1-1,j1-1를 더해주는 방식, 즉 S[i2][j2] - S[i1-1][j2] - S[i2][j1-1] + S[i1-1][j1-1]로 정의됩니다.

백준 11659(구간 합 구하기 4)의 경우 수 N개가 주어졌을 때 i번째 수부터 j번째 수까지의 합을 구하는 문제입니다. 방금 알아본 1차원 누적합 배열을 생성한 후 각 경우에서 S[j]-S[i-1]를 실행합니다.

백준 11660(구간 합 구하기 5) 문제의 경우 NxN 표에서 x1,y1부터 x2,y2까지의 합을 구하는 문제입니다. 위에서 알아본 2차원 누적합 배열을 생성한 후 S[i2][j2] - S[i1-1][j2] - S[i2][j1-1] + S[i1-1][j1-1]로 결과를 구합니다. 여기서 주의할 점은 문제에서 요구하는대로 x와 y방향을 맞춰야 한다는 점입니다. 문제의 입력은 x,y 순서이기 때문에 배열에도 x,y 순서로 넣어야 하며, 만약 y,x 순서로 넣고 싶다면 입력받을 때 먼저 y부터 입력받는 식으로 진행하시면 됩니다.

백준 10986(나머지 합) 문제의 경우 수열의 연속된 부분 구간의 합이 M으로 나누어 떨어지는 구간의 개수를 구하는 문제입니다. 10^6에 대한 모든 구간 합을 구해야 하기 때문에 완전 탐색으로 진행 시 시간 초과가 발생하여 누적합을 진행합니다. 이 때 등식의 결합 법칙으로 인해 누적 합의 나머지 연산과 합 내부의 수들을 나머지 연산을 해서 합한 것과 같기 때문에 누적 합을 생성 후 나머지 연산을 진행합니다. 여기서 나누어 떨어지는 누적합의 경우 0부터 i까지의 구간합이 M으로 나누어 떨어진다는 의미이기 때문에 그 개수만큼 정답에 추가합니다. 또한 i에서 j까지의 합은 S[j] - S[i-1]일 때 나머지 연산을 해도 같은 결과이기 때문에 S[j]%M - S[i-1]%M가 되는데 이 값이 0이 되어야 하므로 S[j]%M == S[i-1]%M, 즉 누적합 원소가 같은 것들 중에서 2개를 선택한 경우의 수를 추가합니다. 여기서 주의할 점은 나머지 연산한 결과 개수를 담는 check 배열은 M으로 나눈 나머지 결과를 담는 배열이기 때문에 M보다 클 수 없게 범위를 설정해주시면 됩니다.

두 번째 유형은 dp와 접목해서 누적합을 구하는 문제입니다. dp 문제에서 알아본 것처럼 특정 패턴이 존재하고 이를 적용 가능할 때 dp와 함께 이용할 수 있습니다.

백준 2228(구간 나누기) 문제의 경우 배열에서 M개의 구간을 선택해서 구간에 속한 수들의 총합의 최댓값을 구하는 문제입니다. dp[i][j] : i개의 수를 j개의 구간을 나누었을 때 최대합이라고 한다면 i번째 수가 j번째 구간에 포함되지 않는 경우는 dp[i][j] = dp[i-1][j], 즉 이전 수가 j번째 구간에 포함될 때의 값을 그대로 가져오며 i번째 수가 j번째 구간에 포함되는 경우 이전 수들 중 총합의 최댓값에 현재 값을 더한, 즉 dp[i][j] = Math.max(dp[k][j-1]) + sum[N] - sum[k+1]로 설정합니다. 여기서 주의할 점은 i개의 수를 j개의 구간으로 나눌 수 없는 경우를 고려해야 하기 때문에 dp를 충분히 작은 수로 초기화하여 dp가 해당 값을 리턴한다면 구간으로 나눌 수 없다는 것을 의미하기 때문에 -1를 리턴합니다.

백준 11066(파일 합치기) 문제의 경우 두 파일을 합치면서 최종적으로 하나의 파일을 완성하는데 필요한 비용의 최소합을 구하는 문제입니다. dp[i][j] : i번 페이지부터 j번 페이지까지 페이지를 합한 최솟값로 설정한 후 i와 j 사이에 있는 k를 설정해 k의 위치에 따른 페이지 합 최솟값을 출력하여 현재 값을 더하는, 즉 dp[i][j] = dp[i][i+k] + dp[k+1][j] + sum[j] - sum[i-1], k : I+1 ~ j-1, sum[i] = 1부터 i까지의 합으로 설정합니다. 여기서 주의할 점은 탐색을 dp[1][2], dp[2][3] 이렇게 두 페이지의 차가 작은 순서대로 진행하기 때문에 이중 for문에서 i,j를 인덱스로 가져가는 것이 아니라 j,j+i로 가져가서 차이가 작은 순서대로 탐색합니다. 또한 최솟값을 구하는 것이기 때문에 dp 배열을 충분히 큰 수로 초기화해주어야 합니다.

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글