ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 15724번 - 주지수
    알고리즘/백준 2023. 8. 7. 12:29

    1️⃣ 부분합

     

    ✏️ 풀이 과정

    N, M이 최대 1024, 즉 격자의 수가 대략 100만개이고 범위의 개수도 10만개이기 때문에 반드시 부분합을 이용해서 O(N)에 해결해야 합니다. 1차원이 아닌 2차원 부분합을 적용해야 하는데 방법은 아래 그림과 같습니다. 부분합의 각 좌표는 1,1부터 x,y까지의 합을 의미합니다.

    일반화하면 (x2, y2)에서 (x1-1, y2)와 (x2, y1-1)을 빼고 두 번 감산된 (x1-1, y1-1)을 한 번 더해줌으로써 항상 원하는 영역의 합을 얻을 수 있습니다.

     

    위의 부분합 이차원 배열을 만드는 방법은 각자 다를 수 있지만 아래 코드에서는 열 방향으로 일차원 부분합을 우선 구하고 바로 윗 행의 부분합 결과를 더해주는 방법으로 만들었습니다.

     

    ⏱ 시간 복잡도

    계산 자체는 참조 4번으로 끝나기 때문에 부분합을 만드는 O(N * M)이 전체 시간복잡도가 됩니다. 만약 K가 N*M보다 커질 수 있는 경우에는 K도 고려하여 O(N * M + K)로 표현할 수 있습니다. 문제의 조건에서는 대략 백만 단위의 계산으로 해결되는 것을 예측할 수 있습니다. 

     

    💻 코드

    Java

    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());
            StringBuilder sb = new StringBuilder();
            int N = Integer.parseInt(st.nextToken());
            int M = Integer.parseInt(st.nextToken());
            int[][] pSum = new int[N+1][M+1];
            for(int i=1;i<=N;i++) {
            	st = new StringTokenizer(br.readLine());
            	for(int j=1;j<=M;j++) {
            		pSum[i][j] = pSum[i][j-1] + Integer.parseInt(st.nextToken());
            	}
            	for(int j=1;j<=M;j++) {
            		pSum[i][j] += pSum[i-1][j];
            	}
            }
            int K = Integer.parseInt(br.readLine());
            int x1, y1, x2, y2;
            for(int i=0;i<K;i++) {
            	st = new StringTokenizer(br.readLine());
            	x1 = Integer.parseInt(st.nextToken());
            	y1 = Integer.parseInt(st.nextToken());
            	x2 = Integer.parseInt(st.nextToken());
            	y2 = Integer.parseInt(st.nextToken());
            	sb.append(pSum[x2][y2] - pSum[x2][y1-1] - pSum[x1-1][y2] + pSum[x1-1][y1-1] +"\n");
            }
            System.out.print(sb);
            br.close();
        }
    }

    JavaScript

    const input = require("fs")
        .readFileSync(process.platform === "linux" ? "/dev/stdin" : "input.txt")
        .toString()
        .trim()
        .split("\n");
    
    const [N, M] = input[0].split(" ").map(Number);
    const pSum = Array.from(Array(N + 1), () => Array(M + 1).fill(0));
    for (let i = 1; i <= N; i++) {
        input[i].split(" ").map((item, j) => {
            pSum[i][j + 1] = pSum[i][j] + Number(item);
        });
        pSum[i].map((_, j) => {
            pSum[i][j + 1] += pSum[i - 1][j + 1];
        });
    }
    
    const K = Number(input[N + 1]);
    const ans = [];
    for (let i = N + 2; i < N + 2 + K; i++) {
        const [x1, y1, x2, y2] = input[i].split(" ").map(Number);
        ans.push(
            pSum[x2][y2] -
                pSum[x1 - 1][y2] -
                pSum[x2][y1 - 1] +
                pSum[x1 - 1][y1 - 1]
        );
    }
    console.log(ans.join("\n"));

     

    '알고리즘 > 백준' 카테고리의 다른 글

    10830번 - 행렬 제곱  (0) 2023.08.09
    9935번 - 문자열 폭발  (0) 2023.08.09
    14003번 - 가장 긴 증가하는 부분 수열 5  (0) 2023.08.06
    5547번 - 일루미네이션  (0) 2023.08.04
    9251번 - LCS  (0) 2023.08.04
Designed by Tistory.