1
+ import java .io .BufferedReader ;
2
+ import java .io .InputStreamReader ;
3
+ import java .util .ArrayDeque ;
4
+ import java .util .Deque ;
5
+ import java .util .StringTokenizer ;
6
+
7
+ public class Main {
8
+
9
+ static int n ;
10
+ static int [][] board ; // 격자 칸
11
+ static int [][] opers ; // 각 년도의 이동 규칙
12
+ static boolean [][] supple ; // 영양제가 있는 위치
13
+
14
+ // 대각선 움직임 구현
15
+ static int [] dy = { 0 , 0 , -1 , -1 , -1 , 0 , 1 , 1 , 1 };
16
+ static int [] dx = { 0 , 1 , 1 , 0 , -1 , -1 , -1 , 0 , 1 };
17
+
18
+ public static void main (String [] args ) throws Exception {
19
+ BufferedReader br = new BufferedReader (new InputStreamReader (System .in ));
20
+ StringTokenizer st = new StringTokenizer (br .readLine ());
21
+ n = Integer .parseInt (st .nextToken ());
22
+ int m = Integer .parseInt (st .nextToken ());
23
+ board = new int [n ][n ];
24
+ supple = new boolean [n ][n ];
25
+ for (int i = 0 ; i < n ; i ++) {
26
+ st = new StringTokenizer (br .readLine ());
27
+ for (int j = 0 ; j < n ; j ++)
28
+ board [i ][j ] = Integer .parseInt (st .nextToken ());
29
+ }
30
+ opers = new int [m ][2 ]; // { 방향, 크기 }
31
+ for (int i = 0 ; i < m ; i ++) {
32
+ st = new StringTokenizer (br .readLine ());
33
+ opers [i ][0 ] = Integer .parseInt (st .nextToken ());
34
+ opers [i ][1 ] = Integer .parseInt (st .nextToken ());
35
+ }
36
+ // 첫 영양제 위치
37
+ supple [n - 2 ][0 ] = true ;
38
+ supple [n - 2 ][1 ] = true ;
39
+ supple [n - 1 ][0 ] = true ;
40
+ supple [n - 1 ][1 ] = true ;
41
+ // 년도만큼 반복
42
+ for (int year = 0 ; year < m ; year ++) {
43
+ move (year ); // 영양제의 움직임 구현
44
+ grow (); // 영양제 위치의 나무 성장
45
+ cut (); // 크기가 2 이상인 나무를 잘라내고 영양제를 심음
46
+ }
47
+ // 남아있는 나무 높이들의 총 합
48
+ int sum = 0 ;
49
+ for (int i = 0 ; i < n ; i ++)
50
+ for (int j = 0 ; j < n ; j ++)
51
+ sum += board [i ][j ];
52
+ System .out .println (sum );
53
+ }
54
+
55
+ // 영양제의 움직임 구현
56
+ private static void move (int year ) {
57
+ // 큐를 이용해 기존 영양제의 위치를 저장
58
+ Deque <int []> dq = new ArrayDeque <>();
59
+ for (int i = 0 ; i < n ; i ++)
60
+ for (int j = 0 ; j < n ; j ++)
61
+ if (supple [i ][j ]) {
62
+ supple [i ][j ] = false ;
63
+ dq .offer (new int [] { i , j });
64
+ }
65
+ // 년도에 따른 이동 방향 및 크기
66
+ int [] oper = opers [year ];
67
+ while (!dq .isEmpty ()) {
68
+ int [] cur = dq .poll ();
69
+ // 영양제 위치 이동
70
+ int y = (cur [0 ] + dy [oper [0 ]] * oper [1 ] + n ) % n ;
71
+ int x = (cur [1 ] + dx [oper [0 ]] * oper [1 ] + n ) % n ;
72
+ supple [y ][x ] = true ; // 이동한 영양제 위치 표시
73
+ board [y ][x ]++; // 영양제가 있는 위치의 나무 성장
74
+ }
75
+ }
76
+
77
+ // 영양제 위치의 나무 성장
78
+ private static void grow () {
79
+ for (int i = 0 ; i < n ; i ++)
80
+ for (int j = 0 ; j < n ; j ++)
81
+ // 영양제가 있다면
82
+ if (supple [i ][j ]) {
83
+ int cnt = 0 ;
84
+ for (int k = 1 ; k <= 4 ; k ++) {
85
+ // 대각선 벡터값
86
+ int y = i + dy [k * 2 ];
87
+ int x = j + dx [k * 2 ];
88
+ if (isValid (y , x ) && board [y ][x ] > 0 )
89
+ cnt ++;
90
+ }
91
+ // 대각선에 있는 나무의 수 만큼 성장
92
+ board [i ][j ] += cnt ;
93
+ }
94
+ }
95
+
96
+ // 크기가 2 이상인 나무를 잘라내고 영양제를 심음
97
+ private static void cut () {
98
+ for (int i = 0 ; i < n ; i ++)
99
+ for (int j = 0 ; j < n ; j ++)
100
+ // 영양제가 없었던 좌표에서 크기가 2 이상인 나무
101
+ if (!supple [i ][j ]) {
102
+ if (board [i ][j ] >= 2 ) {
103
+ board [i ][j ] -= 2 ;
104
+ supple [i ][j ] = true ;
105
+ }
106
+ } else {
107
+ // 기존에 있던 영양제는 없애줌
108
+ supple [i ][j ] = false ;
109
+ }
110
+ }
111
+
112
+ private static boolean isValid (int y , int x ) {
113
+ return 0 <= y && y < n && 0 <= x && x < n ;
114
+ }
115
+ }
0 commit comments