[Baekjoon] 11660. 구간 합 구하기

2 minute read

문제 설명

문제

N×N개의 수가 N×N 크기의 표에 채워져 있다. (x1, y1)부터 (x2, y2)까지 합을 구하는 프로그램을 작성하시오. (x, y)는 x행 y열을 의미한다.

예를 들어, N = 4이고, 표가 아래와 같이 채워져 있는 경우를 살펴보자.

1 2 3 4
2 3 4 5
3 4 5 6
4 5 6 7

여기서 (2, 2)부터 (3, 4)까지 합을 구하면 3+4+5+4+5+6 = 27이고, (4, 4)부터 (4, 4)까지 합을 구하면 7이다.

표에 채워져 있는 수와 합을 구하는 연산이 주어졌을 때, 이를 처리하는 프로그램을 작성하시오.

입력

첫째 줄에 표의 크기 N과 합을 구해야 하는 횟수 M이 주어진다. (1 ≤ N ≤ 1024, 1 ≤ M ≤ 100,000) 둘째 줄부터 N개의 줄에는 표에 채워져 있는 수가 1행부터 차례대로 주어진다. 다음 M개의 줄에는 네 개의 정수 x1, y1, x2, y2 가 주어지며, (x1, y1)부터 (x2, y2)의 합을 구해 출력해야 한다. 표에 채워져 있는 수는 1,000보다 작거나 같은 자연수이다. (x1 ≤ x2, y1 ≤ y2)

출력

총 M줄에 걸쳐 (x1, y1)부터 (x2, y2)까지 합을 구해 출력한다.

예제 입력 1

4 3
1 2 3 4
2 3 4 5
3 4 5 6
4 5 6 7
2 2 3 4
3 4 3 4
1 1 4 4

예제 출력 1

27
6
64

예제 입력 2

2 4
1 2
3 4
1 1 1 1
1 2 1 2
2 1 2 1
2 2 2 2

예제 출력 2

1
2
3
4

출처

  • 문제를 만든 사람: baekjoon
  • 어색한 표현을 찾은 사람: f52985
  • 빠진 조건을 찾은 사람: kyma123

알고리즘 분류


문제 풀이

# Dynamic Programming

누적합을 이용하는 동적 계획법 문제입니다.


풀이 과정

누적합을 이용하는 문제입니다.

좀 더 쉬운 문제들에서는 ‘행 방향’ 누적합 만을 이용했다면, 이 문제에서는 2차원 리스트에서 ‘행 방향’과 ‘열 방향’ 누적합을 모두 이용해야 합니다.

예제 입력 1로 예시를 들어보겠습니다.

처음 입력을 받았을 때는 아래와 같습니다.

1 2 3 4
2 3 4 5
3 4 5 6
4 5 6 7

여기서 행 방향으로 누적합을 구하면 아래와 같습니다.

1 3 6 10
2 5 9 14
3 7 12 18
4 9 15 22

여기에 열 방향 누적합까지 구합니다.

1 3 6 10
3 8 15 24
6 15 27 42
10 24 42 64

그럼 위 상태에서 입력으로 2 2 3 4가 들어왔다고 하겠습니다.

(3, 4) 위치에 있는 수 42는 1행~3행, 1열~4열의 수를 전부 더한 값입니다. 여기서 1행의 값들과 1열의 값들은 제외해주어야 합니다.

따라서 1행 1열~4열의 누적합인 (1, 4) 위치의 수 10과 1열 1행~3행의 누적합인 (3, 1) 위치의 6을 빼줍니다.

빼주는 과정에서 (1, 1) 위치의 수 1이 두번 빼지므로, 한 번 더해줍니다.

그러면 답을 구할 수 있고, 이로부터 아래와 같은 식을 도출할 수 있습니다.

result = matrix[i2][j2] - matrix[i2][j1-1] - matrix[i1-1][j2] + matrix[i1-1][j1-1]


전체 코드

전체 코드입니다.

실제 코드에서는 구현의 편의를 위해 각 행, 열의 맨 앞에 0 값으로 패딩해줍니다.

import sys
input = sys.stdin.readline

N, M = map(int, input().split())
matrix = [[0 for _ in range(N+1)] for _ in range(N+1)]
for i in range(1, N+1):
    nums = list(map(int, input().split()))
    for j in range(1, N+1):
        matrix[i][j] = matrix[i][j-1] + nums[j-1]
print(*matrix, sep='\n')
for i in range(1, N+1):
    for j in range(1, N+1):
        matrix[i][j] += matrix[i-1][j]
print(*matrix, sep='\n')
for _ in range(M):
    i1, j1, i2, j2 = map(int, input().split())
    result = matrix[i2][j2] - matrix[i2][j1-1] - matrix[i1-1][j2] + matrix[i1-1][j1-1]
    print(result)


배운 점

  • 구간합 문제에서는 누적합을 계산하여 실제 값을 계산할 때는 인덱싱으로 1번의 단순 연산(for문 없이)만 하면 되도록 구현한다.
  • 누적합을 이용할 때는 구현의 편의를 위해 각 행/열의 맨 앞에 0으로 패딩을 해준다.

Leave a comment