백준 월간 향유회 2026. 01-02. Open Contest 후기
1. 후기
전날 2026 KSA Automata Winter Contest에 이어서 월간 향유회 2026. 01-02. Open Contest에 참여했다. 역시나 Solved.ac 뱃지나 배경을 받을 수 있지 않을까 했고 Java를 쓰기로 마음먹고 참여했다. 이전 월간 향유회 문제들을 보니 플래티넘부터 시작하는 대회도 있어서 A번 문제가 너무 어려우면 바로 포기하기로 마음먹었는데 대회가 시작하자 문제 수가 많고 브론즈 문제부터 시작하는 것 같아서 다행이라고 생각했다. 초반 문제들은 생각보다 전형적인 백준 스타일이 아니라고 느껴졌는데 후에 알고리즘 태그들을 보니 애드 혹이나 해 구성하기가 섞여 있어서 그렇게 느껴졌다.
2. 문제 풀이
A번 [Java]
하나라도 다른 모든 운영진보다 높은 지표가 있으면 후보가 되며 후보의 수를 세는 문제로 2차원 배열로 입력을 받고 이후 열 우선 순회로 최댓값 찾기 및 유일성 비교를 하면 해결되는 것으로 보였다. 타이핑만 하고 제출하니 바로 통과가 돼서 기분이 좋았다. 체감 난이도는 브론즈 1 ~ 2 정도였다.
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
import java.io.*;
import java.util.*;
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());
int n = Integer.parseInt(st.nextToken());
int k = Integer.parseInt(st.nextToken());
boolean[] check = new boolean[n];
int[][] map = new int[n][k];
for (int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < k; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
for (int i = 0; i < k; i++) {
int max = 0;
int cnt = 0;
int idx = 0;
for (int j = 0; j < n; j++) {
if (map[j][i] > max) {
max = map[j][i];
cnt = 1;
idx = j;
} else if (map[j][i] == max) {
cnt++;
}
}
if (cnt == 1) {
check[idx] = true;
}
}
int cnt = 0;
for (boolean flag : check) {
if (flag) cnt++;
}
System.out.println(cnt);
}
}
B번 [Java]
격자에서 변화가 일어나지 않을 때 채운 최대 칸 수와 그때의 시간을 구하는 문제로 처음엔 단순한 최단 시간 BFS인줄 알았다. 사방탐색 조건이 약간 까다롭네 정도로 생각하고 제출했는데 메모리 초과가 나서 다시 보니 격자 크기의 상한이 매우 커서 2차원 배열로 풀 수 없다는 것을 알았다. 제한사항을 꼼꼼히 읽어봐야 함을 다시금 느끼며 바로 수학적 사고로 해결할 수 있겠구나 짐작했다. 느낌적으로 가로 또는 세로 방향으로 전파가 끝나는데 걸리는 시간이 각 방향으로 1초당 전파 거리로 전체 거리를 올림 나눗셈한 몫이겠구나 했는데 특정 방향으로 전파되지 않는 경우가 있었고 이 때문에 모든 격자를 채울 수 없는 것을 알게됐다. 예제가 어떻게 되는지 움짤이 있는데 이걸 좀 꼼꼼히 볼 걸 그랬다. 전파 영역은 위 사항만 고려하면 됐고 전파 시간은 가로 전파 시간과 세로 전파 시간의 합이 정확히 맞는지 약간 확신이 애매했지만 먼저 닿은 벽에서 반대 방향을 채우는게 최단이겠구나 해서 제출하고 풀 수 있었다. 애드 혹 문제 느낌이었고 체감 난이도는 골드 5 정도였는데 지문과 예제 움짤을 꼼꼼히 봤다면 실버 1 ~ 2 정도로도 볼 수 있을 것 같았다.
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
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
StringTokenizer st;
int t = Integer.parseInt(br.readLine());
while (t-- > 0) {
st = new StringTokenizer(br.readLine());
long n = Long.parseLong(st.nextToken());
long m = Long.parseLong(st.nextToken());
long l = Long.parseLong(st.nextToken());
long r = Long.parseLong(st.nextToken());
long u = Long.parseLong(st.nextToken());
long d = Long.parseLong(st.nextToken());
long ht = (u + d == 0) ? 0 : (n - 1 + u + d - 1) / (u + d);
long wt = (l + r == 0) ? 0 : (m - 1 + l + r - 1) / (l + r);
long fill = 1;
if (ht != 0) fill *= n;
if (wt != 0) fill *= m;
sb.append(fill).append(" ").append(ht + wt).append("\n");
}
System.out.println(sb);
}
}
C번 [Java]
합성 함수스러운 수열을 만족하면 출력하고 아니면 $-1$ 을 출력하는 문제로 지문을 이해하기가 약간 어려웠다. $P_1$ 부터 천천히 확장해나가면 $[2, 3, … N, 1]$ 꼴의 수열이 되야하는 것을 볼 수 있고 $N = 1$, $K = 1$ 일 때만 예외 처리를 해주면 되는 것을 알 수 있다. 이것도 애드 혹 문제라고 느껴졌고 체감 난이도는 실버 3 ~ 4 정도였다.
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
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
StringTokenizer st;
int t = Integer.parseInt(br.readLine());
while (t-- > 0) {
st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int k = Integer.parseInt(st.nextToken());
if (n == 1 && k == 1) {
sb.append("1\n");
} else if (k != 2) {
sb.append("-1\n");
} else {
for (int i = 2; i <= n; i++) {
sb.append(i).append(" ");
}
sb.append("1\n");
}
}
System.out.println(sb);
}
}
D번 [Java]
지문을 이해하기 가장 어려웠는데 그냥 일반적인 들여쓰기 규칙을 만족하는지로 이해했다. 들여쓰기 규칙이 현재 들여쓰기 레벨이 닫히면 이전 들여쓰기 레벨의 가장 마지막 수 +1 부터 시작하므로 스택 자료구조를 활용해서 1 이면 확장하고 이전 수보다 1 크면 현재 레벨에 이어 쓸 수 있고 아니면 현재 들여쓰기 레벨을 닫고 이전 들여쓰기 레벨에 붙일 수 있는지 판단하면 되겠다 싶었다. 근데 반례가 있는지 계속 안풀려서 결국은 해결하지 못했다. 체감 난이도는 골드 4 ~ 5 정도였고 스택이 포인트라고 확신했는데 굉장히 아쉬운 문제였다.
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st;
int t = Integer.parseInt(br.readLine());
out:
while (t-- > 0) {
int n = Integer.parseInt(br.readLine());
int[] arr = new int[n];
st = new StringTokenizer(br.readLine());
for (int i = 0; i < n; i++) {
arr[i] = Integer.parseInt(st.nextToken());
}
Deque<Integer> stack = new ArrayDeque<>();
for (int x : arr) {
if (x == 1 || (!stack.isEmpty() && (stack.peek() + 1 == x))) {
stack.push(x);
} else {
if (stack.isEmpty()) {
bw.write("NO\n");
continue out;
} else {
while (!stack.isEmpty() && stack.peek() != 1) {
stack.pop();
}
stack.pop();
if (stack.isEmpty() || stack.peek() + 1 != x) {
bw.write("NO\n");
continue out;
} else {
stack.push(x);
}
}
}
System.out.println(stack);
}
bw.write("YES\n");
}
bw.flush();
}
}
// 1
// 2
// 3
// 1
// 2
// 1
// 1
// 2
// 2
// 1
// 1
// 2
// 1
// 2
// 1
// 2
// 1
// 2
// 3
// 1
//. 1
//. 1
//. 1
//. 2
//. 2
//. 2
//.2
