Algorithm/Baekjoon

백준 / 11659번 / 구간 합 구하기 4 (prefix sum-누적합)

Gyuri 2022. 12. 31. 17:08

[문제]

수 N개가 주어졌을 때, i번째 수부터 j번째 수까지 합을 구하는 프로그램을 작성하시오.

[입력]

첫째 줄에 문자열이 주어진다. 문자열의 길이는 1보다 크거나 같고, 1,000,000보다 작거나 같다.

둘째 줄에 폭발 문자열이 주어진다. 길이는 1보다 크거나 같고, 36보다 작거나 같다.

두 문자열은 모두 알파벳 소문자와 대문자, 숫자 0, 1, ..., 9로만 이루어져 있다.

[출력]

총 M개의 줄에 입력으로 주어진 i번째 수부터 j번째 수까지 합을 출력한다.

[제한]

  • 1 ≤ N ≤ 100,000
  • 1 ≤ M ≤ 100,000
  • 1 ≤ i ≤ j ≤ N

[예제 입력]

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

[예제 출력]

12
9
1

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");

        int N = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());

        int[] arr = new int[N + 1];
        int[] sumArr = new int[N + 1];

        StringTokenizer st2 = new StringTokenizer(br.readLine(), " ");
        for (int i = 1; i < N + 1; i++) {
            arr[i] = Integer.parseInt(st2.nextToken());
            sumArr[i] = sumArr[i - 1] + arr[i];
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < M; i++) {
            StringTokenizer st3 = new StringTokenizer(br.readLine(), " ");

            int a = Integer.parseInt(st3.nextToken());
            int b = Integer.parseInt(st3.nextToken());

            sb.append(sumArr[b] - sumArr[a - 1] + "\n");
        }
        System.out.println(sb);
    }
}

처음에 누적합이라는게 있는줄 모르고, 단순히 배열에 수를 저장한 후

i, j 값을 입력받아 그 부분을 더해줬는데, 당연히 시간초과가 떴다.

 

"누적합" 을 이용해서 푸는 문제여서, 우선 누적합에 대해 찾아봤다.

 


 

누적합

배열에 값을 저장하고 지정된 인덱스부터 하나씩 더해가는 경우 즉, 내가 시도했던 방법은 최악의 경우 O(N^2)의 시간복잡도를 갖기 때문에 입력 범위가 클 땐 사용할 수 없다.

하지만 prefix sum 방식을 사용하면 O(N)으로 해결이 가능하다.

 

예로, 크기가 5인 arr 배열에서 3~5 구간의 구간합을 구한다고 가정하면,

이 누적합은 arr[0~b] 의 누적합 - arr[0~a-1] 의 누적합 으로 표현할 수 있다.

 

 

각 인덱스 값에 해당되는 누적합을 저장한 것이다.

그리고, 3번~5번 구간 사이의 누적합을 구하려면

1번~5번까지의 누적합에서 1번~2번 구간의 누적합을 빼주면 된다!

 

그런식으로 이용하면, 

위의 문제로 예를 들었을 때 길이가 5인 배열에 5 4 3 2 1 이 저장돼있고

1~3 구간의 누적합을 구하려면

1~5 구간의 누적합 - 1~2 구간의 누적합이 정답이 된다.

 

누적합에 대해 잘 몰라서 시간 초과가 뜬 문제인데, 알고보니 어렵지 않다. 

다음에 까먹지 않으려면 누적합 관련 문제를 좀 더 풀어봐야 할 것 같다!

 

참고 : https://jow1025.tistory.com/47