1
+ import java .io .*;
2
+ import java .util .*;
3
+
4
+ public class DH_회전하는_빙하 {
5
+ static class Point {
6
+ int r , c ;
7
+ public Point (int r , int c ) {
8
+ this .r = r ;
9
+ this .c = c ;
10
+ }
11
+ }
12
+ static int N , Q , totalIceCnt , iceSize ;
13
+ static int [][] map ;
14
+ static BufferedReader br ;
15
+ static StringTokenizer st ;
16
+ static int [] dr = {1 , 0 , -1 , 0 }, dc = {0 , 1 , 0 , -1 }; // 하, 우, 상, 좌
17
+ static boolean [][] v ;
18
+ static Deque <Point > q ;
19
+
20
+ public static void main (String [] args ) throws Exception {
21
+ System .setIn (new FileInputStream ("./input/회전하는빙하.txt" ));
22
+ initInput ();
23
+ solution ();
24
+ }
25
+
26
+ static void solution () throws Exception {
27
+ st = new StringTokenizer (br .readLine ());
28
+
29
+ while (Q -- > 0 ) {
30
+ int level = Integer .parseInt (st .nextToken ());
31
+ rotate (level );
32
+ melt ();
33
+ }
34
+
35
+ // map을 확인하며 영역의 최대 크기와 남아있는 얼음의 양 구하기
36
+ checkMapStatus ();
37
+
38
+ StringBuilder sb = new StringBuilder ();
39
+ sb .append (totalIceCnt ).append ("\n " ).append (iceSize );
40
+ System .out .println (sb );
41
+ }
42
+
43
+ static void checkMapStatus () {
44
+ v = new boolean [map .length ][map [0 ].length ];
45
+ q = new ArrayDeque <>();
46
+
47
+ // bfs를 통해 얼음이 있는 영역의 최대 크기와 남아있는 얼음의 양 구하기
48
+ for (int r = 0 ; r < map .length ; r ++) {
49
+ for (int c = 0 ; c < map [0 ].length ; c ++) {
50
+ if (v [r ][c ] || map [r ][c ] == 0 ) continue ;
51
+ bfs (r , c );
52
+ }
53
+ }
54
+ }
55
+
56
+ static void bfs (int r , int c ) {
57
+ q .add (new Point (r , c ));
58
+ v [r ][c ] = true ;
59
+ totalIceCnt += map [r ][c ];
60
+ int size = 1 ;
61
+
62
+ while (!q .isEmpty ()) {
63
+ Point current = q .poll ();
64
+
65
+ for (int d = 0 ; d < 4 ; d ++) {
66
+ int nr = current .r + dr [d ];
67
+ int nc = current .c + dc [d ];
68
+
69
+ if (!check (nr , nc ) || v [nr ][nc ] || map [nr ][nc ] == 0 ) continue ;
70
+ q .add (new Point (nr , nc ));
71
+ v [nr ][nc ] = true ;
72
+ totalIceCnt += map [nr ][nc ];
73
+ size ++;
74
+ }
75
+ }
76
+
77
+ iceSize = Math .max (iceSize , size );
78
+ }
79
+
80
+ // meltFlag[r][c] == true인 지점 녹이기
81
+ static void melt () {
82
+ boolean [][] meltFlag = makeMeltFlagMap ();
83
+ for (int r = 0 ; r < meltFlag .length ; r ++) {
84
+ for (int c = 0 ; c < meltFlag [0 ].length ; c ++) {
85
+ if (!meltFlag [r ][c ] || map [r ][c ] == 0 ) continue ;
86
+ map [r ][c ]--;
87
+ }
88
+ }
89
+ }
90
+
91
+ // 해당 부분이 녹는지 안녹는지 확인하는 meltFlag 변수를 초기화하는 함수
92
+ static boolean [][] makeMeltFlagMap () {
93
+ boolean [][] meltFlag = new boolean [map .length ][map [0 ].length ];
94
+
95
+ for (int r = 0 ; r < map .length ; r ++) {
96
+ for (int c = 0 ; c < map [0 ].length ; c ++) {
97
+ int iceCnt = 0 ;
98
+ for (int d = 0 ; d < 4 ; d ++) {
99
+ int nr = r + dr [d ];
100
+ int nc = c + dc [d ];
101
+
102
+ if (!check (nr , nc ) || map [nr ][nc ] == 0 ) continue ;
103
+ iceCnt ++;
104
+ }
105
+
106
+ if (iceCnt < 3 ) meltFlag [r ][c ] = true ;
107
+ }
108
+ }
109
+ return meltFlag ;
110
+ }
111
+ static boolean check (int r , int c ) {
112
+ return r >= 0 && r < map .length && c >= 0 && c < map [0 ].length ;
113
+ }
114
+ static void rotate (int level ) {
115
+ int size = (int ) Math .pow (2 , level );
116
+ // r, c: 하늘색 사각형 배열이 시작하는 부분
117
+ for (int r = 0 ; r < map .length ; r += size ) {
118
+ for (int c = 0 ; c < map [0 ].length ; c += size ) {
119
+
120
+ // map에서 1사분면만 해당되는 부분을 저장
121
+ int [][] tmp = copyPart1 (r , c , size / 2 );
122
+ rotate (r , c , level , tmp );
123
+ }
124
+ }
125
+ }
126
+
127
+ static int [][] copyPart1 (int r , int c , int level ) {
128
+ int [][] tmp = new int [level ][level ];
129
+ for (int sr = r ; sr < r + level ; sr ++) {
130
+ for (int sc = c ; sc < c + level ; sc ++) {
131
+ tmp [sr - r ][sc - c ] = map [sr ][sc ];
132
+ }
133
+ }
134
+
135
+ return tmp ;
136
+ }
137
+
138
+ static void rotate (int r , int c , int level , int [][] tmp ) {
139
+
140
+ int size = (int ) Math .pow (2 , level ) / 2 ;
141
+
142
+ // 반시계 방향으로 돌면서 바꿀 값을 가지고 옴
143
+ for (int i = 0 ; i < 3 ; i ++) {
144
+
145
+ int nr = r + dr [i ] * size ;
146
+ int nc = c + dc [i ] * size ;
147
+
148
+ // rr, cc: 첨부한 사진 level2에서 민트색(?) 부분 배열
149
+ // level1에서는 크기가 1 * 1이기 때문에 사진에 표시 안함
150
+ for (int rr = 0 ; rr < size ; rr ++) {
151
+ for (int cc = 0 ; cc < size ; cc ++) {
152
+ map [r + rr ][c + cc ] = map [nr + rr ][nc + cc ];
153
+ }
154
+ }
155
+
156
+ r = nr ; c = nc ;
157
+ }
158
+
159
+ // 처음 부분은 이미 값이 바뀐 상태이기 때문에
160
+ // 미리 tmp 값에 저장한 값으로 가져옴
161
+ for (int rr = 0 ; rr < size ; rr ++) {
162
+ for (int cc = 0 ; cc < size ; cc ++) {
163
+ map [r + rr ][c + cc ] = tmp [rr ][cc ];
164
+ }
165
+ }
166
+ }
167
+
168
+ static void printMap () {
169
+ for (int r = 0 ; r < map .length ; r ++) {
170
+ System .out .println (Arrays .toString (map [r ]));
171
+ }
172
+ }
173
+
174
+ static void initInput () throws Exception {
175
+ br = new BufferedReader (new InputStreamReader (System .in ));
176
+ st = new StringTokenizer (br .readLine ());
177
+
178
+ N = Integer .parseInt (st .nextToken ());
179
+ Q = Integer .parseInt (st .nextToken ());
180
+
181
+ int length = (int ) Math .pow (2 , N );
182
+ map = new int [length ][length ];
183
+
184
+ for (int r = 0 ; r < map .length ; r ++) {
185
+ st = new StringTokenizer (br .readLine ());
186
+
187
+ for (int c = 0 ; c < map [0 ].length ; c ++) {
188
+ map [r ][c ] = Integer .parseInt (st .nextToken ());
189
+ }
190
+ }
191
+
192
+
193
+ }
194
+ }
0 commit comments