Post

[2022 KAKAO BLIND RECRUITMENT] 파괴되지 않은 건물

[2022 KAKAO BLIND RECRUITMENT] 파괴되지 않은 건물

🙋‍♂️ 들어가며

이번 문제는 단순한 반복문으로 접근하면 시간초과가 나는 문제였다.

최악의 경우 1000 * 1000 * 25000이기에 무조건 시간초과다.

그래서 누적합을 사용해야했다 차변을 사용한 누적합 말이다.

🤔누적합이 무엇인가??

편의상 차변 추가를 위해 새로운 diff 배열은 [row + 1][col + 1] 로 만들자

0,0 ~ 3,4까지 (v = -4) 만큼 채우고싶다.

      
-40000+4
000000
000000
000000
+40000-4

열방향, 행방향에 더이상 퍼지는 것을 막기위해 테두리의 er+1, ec+1에 각각 -v를 추가했다.

근데 굳이 여기서 diff[er+1][ec+1] = v 를 왜 추가해야할까??

그 이유는 행과 열의 누적합을 2단계로 계산하면 알게된다.

먼저 행계산

1️⃣ 행계산

      
-4-4-4-4-40
000000
000000
000000
+4+4+4+4+40

그 이후 열계산

2️⃣ 열계산

      
-4-4-4-4-40
-4-4-4-4-40
-4-4-4-4-40
-4-4-4-4-40
000000


⭐오오오

원하는대로 0,0 ~ 3,4까지 -4가 전부 채워졌군

이제 DP 누적합에 대해 알았으니 본격적으로 풀이를 시작하도록 하겠다.

풀이

testcase 1번 기준으로 skill은 4회다.

0번째 skill -> 0,0 ~ 3,4까지 -4만큼 공격

1번째 skill -> 2,0 ~ 2,3까지 -2만큼 공격

2번째 skill -> 1,0 ~ 3,1까지 +2만큼 회복

3번째 skill -> 0,1 ~ 3,3까지 -1만큼 공격


Desktop View
위는 0번째 공격을 하여 diff만큼 배열에 값을 추가했다.

Desktop View
근데 편의상 마지막에 계산할때는 검은색으로 칠한 테두리의 영역은 보지 않아도 될 것 같다.

아무튼 이어서 1,2,3 번째 skill을 시전하면 다음 사진과 같아진다.

Desktop View

먼저 행계산부터, 그 이후 열계산

1️⃣ 행계산

      
-4-5-5-5-40
220000
-2-2-2-200
222200
+2+1+1+1+0-4

2️⃣ 열계산

      
-4-5-5-5-40
-2-3-5-5-40
-4-4-7-7-40
-2-3-5-5-40
0-2-4-4-4-4

여기서 의아할 것이다.

아니? 누적합하면 테두리의 경계까지 다 합산 했을때 0이 나와야하는데 왜 테두리가 0이 아니지??

1차원 누적은 배열 마지막이 항상 0으로 돌아온다.

그러나 2차원은 테두리가 0이 아닐 수 있으므로 내가 잘못 구했다고 생각하지말자.

참 아까 검은 테두리 영역은 필요없다고 했으니 4*5 영역만 누적합 영역만 다시 보겠다

행 계산을 하면 아래와 같다

1️⃣ 행계산

     
-4-5-5-5-4
22000
-2-2-2-20
22220

다음은 열계산이다

2️⃣ 열계산

     
-4-5-5-5-4
-2-3-5-5-4
-4-4-7-7-4
-2-3-5-5-4


이제 이 상태에서 완전탐색을 통해

arr[r][c] + diff[r][c] > 0 -> cnt++

이렇게 구해주면 되겠다

이것의 시간복잡도는 다음과 같겠다

O(T + (row * col) )

즉 O(250,000 + 1,000,000)


✅ 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
class Solution {
    public int solution(int[][] board, int[][] skill) {
        int cnt = 0;
        
        int row = board.length;
        int col = board[0].length;
        
        // 차분을 이용하자
        // 이후 마지막 idx인 row, col은 이용하지않는다
        // idx는 누적합시 row-1, col-1 까지만 이용하자
        long[][] diff = new long[row+1][col+1];
        
        
        int T = skill.length;
        for (int t = 0; t < T; t++) {
            int type = skill[t][0];
            int sr = skill[t][1];
            int sc = skill[t][2];
            int er = skill[t][3];
            int ec = skill[t][4];
            int degree = skill[t][5];
            
            // 공격일때 음수처리
            if (type == 1) {
                degree = -degree;
            }
            
            // 1-1. 왼쪽 맨위끝 모서리
            diff[sr][sc] += degree;
            
            // 1-2. 왼쪽 맨위 우측끝 모서리
            diff[sr][ec+1] += -degree;
            
            // 1-3. 왼쪽 맨아래 맨밑 모서리
            diff[er+1][sc] += -degree;
            
            // 1-4. 맨 오른쪽 밑 끝 모서리
            diff[er+1][ec+1] += degree;
        }
        
        
        // 2. 행방향 누적합
        for (int r = 0; r < row; r++) {
            for (int c = 1; c < col; c++) {
                diff[r][c] += diff[r][c-1];
            }
        }
        
        // 3. 열방향 누적합
        for (int r = 1; r < row; r++) {
            for (int c = 0; c < col; c++) {
                diff[r][c] += diff[r-1][c];
            }
        }
        
        // 4. 결과
        for (int r = 0; r < row; r++) {
            for (int c = 0; c < col; c++) {
                if (board[r][c] + diff[r][c] > 0) cnt++;
            }
        }
        
        return cnt;
    }
}
This post is licensed under CC BY 4.0 by the author.
3D GIF

Trending Tags

도움이 필요하면
나를 눌러 구리🐻
챗봇
너굴
bot
어서와 구리 ʕ ·ᴥ·ʔ
무엇이 필요하셔 구리?

Trending Tags

도움이 필요하면
나를 눌러 구리🐻
챗봇
너굴
bot
어서와 구리 ʕ ·ᴥ·ʔ
무엇이 필요하셔 구리?