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 JW_Sam의_피자학교 {
8
+
9
+ static int n , k ;
10
+ static Deque <Integer > dq = new ArrayDeque <>();
11
+ static int maxValue = 0 , minValue = 3001 ;
12
+ static int H , W , R ; // 초기 크기
13
+ static int h , w , r ; // 변하는 크기
14
+ static int [][] dough ; // 피자 도우
15
+ static int [] dy = { 0 , -1 , 0 , 1 }, dx = { -1 , 0 , 1 , 0 };
16
+
17
+ public static void main (String [] args ) throws Exception {
18
+ BufferedReader br = new BufferedReader (new InputStreamReader (System .in ));
19
+ StringTokenizer st = new StringTokenizer (br .readLine ());
20
+ n = Integer .parseInt (st .nextToken ());
21
+ k = Integer .parseInt (st .nextToken ());
22
+ st = new StringTokenizer (br .readLine ());
23
+ int v ;
24
+ for (int i = 0 ; i < n ; i ++) {
25
+ v = Integer .parseInt (st .nextToken ());
26
+ dq .offer (v );
27
+ maxValue = Math .max (maxValue , v );
28
+ minValue = Math .min (minValue , v );
29
+ }
30
+ calculateDoughSize (); // 빙글빙글 접을 때의 사이즈 계산
31
+ int time = 0 ;
32
+ while (maxValue - minValue > k ) {
33
+ initDough (); // 빙글빙글 접기
34
+ press (); // 누르기
35
+ outspread (); // 펼치기
36
+ halfDough (); // 절반씩 접기
37
+ press (); // 누르기
38
+ outspread (); // 펼치기
39
+ judge (); // 최대, 최솟값 갱신
40
+ time ++;
41
+ }
42
+ System .out .println (time );
43
+ }
44
+
45
+ // 빙글빙글 말 떄의 사이즈 계산
46
+ private static void calculateDoughSize () {
47
+ int i = 0 ;
48
+ while ((int ) ((i + 4 ) / 2 ) * (int ) ((i + 3 ) / 2 ) <= n )
49
+ i ++;
50
+ H = (i + 3 ) / 2 ;
51
+ W = (i + 2 ) / 2 ;
52
+ R = n - H * W ;
53
+ }
54
+
55
+ // 빙글빙글 접기
56
+ private static void initDough () {
57
+ h = H ;
58
+ w = W ;
59
+ r = R ;
60
+ dough = new int [h ][w + r ];
61
+ // 사용하면 안되는 곳에 -1값 삽입
62
+ for (int i = 0 ; i < h - 1 ; i ++)
63
+ for (int j = 0 ; j < r ; j ++)
64
+ dough [i ][w + j ] = -1 ;
65
+ int y = h - 1 , x = w + r - 1 , dir = 0 ;
66
+ while (!dq .isEmpty ()) {
67
+ dough [y ][x ] = dq .pollLast ();
68
+ if (dough [y ][x ] == minValue )
69
+ dough [y ][x ]++;
70
+ // 부딪히거나 값이 있는 곳이라면 회전
71
+ if (!isValid (y + dy [dir ], x + dx [dir ]) || dough [y + dy [dir ]][x + dx [dir ]] != 0 )
72
+ dir = (dir + 1 ) % 4 ;
73
+ y += dy [dir ];
74
+ x += dx [dir ];
75
+ }
76
+ }
77
+
78
+ // 절반씩 접기
79
+ private static void halfDough () {
80
+ h = 4 ;
81
+ w = n / 4 ;
82
+ r = 0 ;
83
+ dough = new int [h ][w ];
84
+ for (int i = w - 1 ; i >= 0 ; i --)
85
+ dough [3 ][i ] = dq .pollLast ();
86
+ for (int i = w - 1 ; i >= 0 ; i --)
87
+ dough [2 ][i ] = dq .pollFirst ();
88
+ for (int i = 0 ; i < w ; i ++)
89
+ dough [1 ][i ] = dq .pollFirst ();
90
+ for (int i = 0 ; i < w ; i ++)
91
+ dough [0 ][i ] = dq .pollLast ();
92
+ }
93
+
94
+ // 누르기
95
+ private static void press () {
96
+ int [][] temp = new int [h ][w + r ]; // 변화량을 저장할 배열
97
+ int ny , nx , d ;
98
+ for (int y = 0 ; y < h ; y ++)
99
+ for (int x = 0 ; x < w + r ; x ++) {
100
+ // 사용하지 않는 칸 스킵
101
+ if (dough [y ][x ] == -1 )
102
+ continue ;
103
+ for (int dir = 2 ; dir < 4 ; dir ++) {
104
+ ny = y + dy [dir ];
105
+ nx = x + dx [dir ];
106
+ // 좌 하에서 평균 계산 후 맞춰주기
107
+ if (isValid (ny , nx ) && dough [ny ][nx ] != -1 ) {
108
+ d = Math .abs (dough [y ][x ] - dough [ny ][nx ]) / 5 ;
109
+ if (dough [y ][x ] > dough [ny ][nx ]) {
110
+ temp [y ][x ] -= d ;
111
+ temp [ny ][nx ] += d ;
112
+ } else if (dough [y ][x ] < dough [ny ][nx ]) {
113
+ temp [y ][x ] += d ;
114
+ temp [ny ][nx ] -= d ;
115
+ }
116
+ }
117
+ }
118
+ }
119
+ // 변화량 계산
120
+ for (int y = 0 ; y < h ; y ++)
121
+ for (int x = 0 ; x < w + r ; x ++) {
122
+ if (temp [y ][x ] == 0 )
123
+ continue ;
124
+ dough [y ][x ] += temp [y ][x ];
125
+ }
126
+ }
127
+
128
+ // 펼치기
129
+ private static void outspread () {
130
+ maxValue = 0 ;
131
+ minValue = 3001 ;
132
+ for (int x = 0 ; x < w + r ; x ++)
133
+ for (int y = h - 1 ; y >= 0 ; y --) {
134
+ if (dough [y ][x ] == -1 )
135
+ break ;
136
+ dq .offer (dough [y ][x ]);
137
+ }
138
+ }
139
+
140
+
141
+ // 최댓값 최솟값 갱신
142
+ private static void judge () {
143
+ for (int y = 0 ; y < h ; y ++)
144
+ for (int x = 0 ; x < w ; x ++) {
145
+ maxValue = Math .max (maxValue , dough [y ][x ]);
146
+ minValue = Math .min (minValue , dough [y ][x ]);
147
+ }
148
+ }
149
+
150
+ // 유효성 검사
151
+ private static boolean isValid (int y , int x ) {
152
+ return 0 <= y && y < h && 0 <= x && x < w + r ;
153
+ }
154
+ }
0 commit comments