• 대회 풀이
  • 2022 연세대학교 미래캠퍼스 슬기로운 코딩생활

2022 연세대학교 미래캠퍼스 슬기로운 코딩생활

A번 - 영수증

영수증에는 구매한 각 물건의 가격과 개수, 구매한 물건의 총 금액이 있습니다.

이 문제는 구매한 물건의 가격과 개수로 계산한 총 금액이 영수증에 적힌 구매한 물건의 총 금액과 일치하는지 확인하는 문제입니다.

각 물건의 가격과 개수를 곱한 값을 모두 더한 값이 영수증에 적힌 구매한 물건의 총 금액과 일치하는지 확인하면 됩니다.

소스 1

B번 - 커트라인

$N$명이 참가한 대회에서 점수가 높은 상위 $k$명은 상을 받게 됩니다. 여기서 상을 받는 커트라인을 구하는 문제입니다. 문제에서 커트라인은 상을 받는 사람 중 점수가 가장 낮은 사람의 점수를 의미한다고 합니다. 즉, 커트라인은 점수가 $k$번째로 높은 사람의 점수를 의미하게 됩니다.

따라서, 이 문제는 입력으로 주어진 점수를 정렬한 다음, $k$번째로 높은 점수를 찾으면 됩니다.

소스 2

입력으로 주어진 점수를 a에 저장했고, 이를 오름차순 정렬했습니다. 1번째로 점수가 높은 사람의 점수는 a[n-1]입니다. 2번째로 높은 사람의 점수는 a[n-2]입니다. 그럼 k번째로 점수가 높은 사람의 점수는 a[n-k]임을 알 수 있습니다.

만약, a를 내림차순 정렬했다면, k번째 점수가 높은 사람의 점수는 a[k-1]에 있게됩니다. 소스 3은 내림차순 정렬을 한 경우입니다.

소스 3

Java에서 Collections.reverseOrder()을 사용하기 위해 a의 선언을 소스 2와 다르게 Integer로 변경했습니다.

소스 2와 3 모두 시간 복잡도는 $O(N \lg N)$ 정렬을 사용하고 있기 때문에, $O(N \lg N)$ 입니다.

$N$의 최댓값은 $1\,000$이기 때문에, $O(N^2)$ 정렬을 사용해도 됩니다.

C번 - 연속 XOR

$A$부터 $B$까지 모든 자연수를 XOR 연산한 값을 구하는 문제입니다. XOR 연산은 $\oplus$로 표시하겠습니다.

소스 4와 같이 해결할 수 있을 것 같지만, 다음과 같이 구현하면 를 받게 됩니다.

소스 4

이유는 $A$와 $B$의 제한 때문입니다.

  • $1 ≤ A ≤ B ≤ 1\,000\,000\,000\,000\,000\,000 = 10^{ 18 }$

소스 4의 시간 복잡도는 $O(B-A+1)$로 계산할 수 있는데, 만약 $A = 1$, $B = 10^{ 18 }$이라면, $10^{ 18 }$개의 $\oplus$ 연산을 수행해야 하기 때문에, 시간이 매우 오래 걸리게 됩니다.

이 문제를 해결하려면 $\oplus$의 성질 하나를 알아야 합니다.

  1. $A \oplus A = 0$

$0 \oplus 0 = 0$이고, $1 \oplus 1 = 0$ 입니다. 같은 수를 $\oplus$연산하면 모든 비트가 같기 때문에, 그 결과는 $0$이 됩니다.

만약 $1$부터 $A-1$까지 모든 자연수를 $\oplus$ 연산한 결과를 $SA$라고 하고 $1$부터 $B$까지 모든 자연수를 $\oplus$ 연산한 결과를 $SB$라고 해봅시다. $SA$와 $SB$를 이용해서 $A$부터 $B$까지 모든 자연수를 $\oplus$한 결과를 구할 수 있습니다. 정답은 바로 $SA \oplus SB$ 입니다.

$SA$와 $SB$를 $\oplus$연산하게 되면, $1$부터 $A-1$까지 자연수는 두 번씩 $\oplus$한 것과 같습니다. 따라서, $A$부터 $B$까지 자연수를 $\oplus$한 결과와 같게 됩니다.

이 아이디어를 이용해 소스 5를 구현할 수 있습니다.

소스 5

소스 5의 f(n)은 $1$부터 n까지 $\oplus$한 결과를 구하는 함수입니다. 소스 4와 마찬가지로 수를 하나씩 $\oplus$하는 것이니 시간 복잡도도 소스 4와 같습니다.

f(1)부터 f(15)까지 순서대로 값을 출력해보면 특이한 규칙을 찾을 수 있습니다.

nf(n)n의 이진수 표현f(n)의 이진수 표현
1100010001
2300100011
3000110000
4401000100
5101010001
6701100111
7001110000
8810001000
9110010001
101110101011
11010110000
121211001100
13111010001
141511101111
15011110000

n을 $4$로 나눈 나머지에 따라서 다음과 같은 규칙을 갖는 것을 확인할 수 있습니다.

  • $4$로 나눈 나머지가 $0$: n
  • $4$로 나눈 나머지가 $1$: 1
  • $4$로 나눈 나머지가 $2$: n+1
  • $4$로 나눈 나머지가 $3$: 0

이를 이용해 소스 6을 구현할 수 있습니다.

소스 6

D번 - 시루의 백화점 구경

문제의 조건을 정리해보겠습니다.

  1. 백화점은 세로 길이가 $N$, 가로 길이가 $M$인 격자 형태
  2. 상하좌우로 인접한으로 이동할 때마다 $1$만큼의 체력을 소모
  3. 기둥이 있는 칸으로는 이동할 수 없음
  4. 마네킹과의 거리가 $K$ 이하인 칸은 이동할 수 없음
  5. 시루가 있는 위치에서 출발해 의자 중 하나에 도착할 때 소모하는 체력의 최솟값을 구해야 함

격자에서 이동하는 문제이고, 이때 이동할때 비용이 1입니다. 이러한 경우 문제에서 구해야 하는 값이 비용의 최솟값이라면 BFS 알고리즘으로 해결할 수 있습니다.

4번 조건이 없다면 시루가 있는 위치를 시작점으로, 의자의 위치를 도착점으로 하는 BFS로 해결할 수 있습니다. 이때 시간 복잡도는 $O(NM)$이 됩니다.

이제 4번 조건이 있는 경우를 생각해봅시다. 어떤 칸으로 이동할 수 있는지 없는지 알아볼때마다 그 칸과 모든 마네킹과의 거리를 구하고, $K$ 이하가 아닌지 확인해야 합니다. 어떤 칸과 모든 마네킹과의 거리가 $K$이하가 아닌지 확인하려면, 그 칸과 가장 가까운 마네킹과의 거리만 구해도 됩니다.

마네킹은 최대 $NM-2$개 있을 수 있으니, 어떤 칸을 이동하려고 할 때마다 가장 가까운 마네킹과의 거리를 구하게 BFS를 구현하면 $O(NMNM)$이 됩니다. $N, M \le 2\,000$이니 시간 초과를 피할 수 없습니다.

격자판에서 $A$에서 $B$까지의 거리는 $B$에서 $A$까지의 거리와 같습니다. 마네킹은 이동하지 않으니 어떤 칸과 가장 가까운 마네킹과의 거리도 변하지 않습니다. 두 칸 $(r_x, c_x), (r_y, c_y)$의 거리는 $\vert r_x-r_y \vert + \vert c_x-c_y \vert$이고, 이 값은 격자에서 $A$에서 $B$로 가는 최단 거리와 같습니다. 따라서, BFS를 하기 전에, 모든 마네킹을 출발점으로 하는 또다른 BFS 알고리즘을 이용해 각 칸과 가장 가까운 마네킹과의 거리를 미리 구해놓을 수 있습니다. 이 과정은 $O(NM)$이 걸립니다.

위에서 한 것 처럼 각 칸과 가장 가까운 마네킹과의 거리를 미리 구했다면, 문제의 정답을 구하는 BFS도 $O(NM)$에 구할 수 있습니다.

소스 7

mane[i][j]에는 (i, j)에서 가장 가까운 마네킹과의 거리를 저장합니다. 마네킹과의 거리를 구할 때는 벽이 의미없으니 이전에 방문했는지 아닌지만 검사하면 됩니다.

격자에 마네킹이 없는 경우를 조심해야 합니다. 만약, 마네킹이 없다면 mane[i][j]에는 $-1$이 들어갈 것이고, 이렇게 되면 이후 가장 가까운 마네킹과의 거리를 계산할 때 잘못된 값과 계산을 하게 되어 정답을 구할 수 없게 됩니다. 따라서, 마네킹의 수를 cnt에 저장했고, 없는 경우 기둥이 아닌 모든 칸을 방문할 수 있는 것이니 k+1을 저장해 모든 칸과 가장 가까운 마네킹과의 거리를 k보다 크게 만들었습니다.

이후 4의 위치를 큐에 넣고 BFS를 수행했고, 최종적으로 시루가 찾아갈 수 있는 의자 중 가장 체력 소모가 적은 것을 찾아 정답으로 출력했습니다.

E번 - 방사형 그래프

문제가 두 개의 부분으로 나누어져 있습니다.

  1. 능력치를 배열
  2. 배열한 능력치가 볼록 다각형을 만드는지 확인

능력치의 개수는 항상 $8$개이고, 이 값을 $N$이라고 하겠습니다. 능력치를 배열하는 방법은 $N! = 8! = 40\,320$개가 있습니다.

능력치를 배열했다고 가정하고, 배열한 능력치가 볼록 다각형을 만드는지 확인하는 방법을 알아보겠습니다.

방사형 그래프는 중심을 원점으로 하는 좌표 평면으로 나타낼 수 있습니다.

$1$번째, $5$번째 꼭짓점은 $y$축에 있고, 좌표는 $(0, a_1)$, $(0, -a_5)$입니다. $3$번째, $7$번째 꼭짓점은 $x$축에 있고, 좌표는 $(a_3, 0)$, $(-a_7, 0)$입니다.

$2$번째 꼭짓점의 좌표는 어떻게 구할 수 있을까요? $2$번째 꼭짓점은 $x$축과 $45^\circ$ 각도를 이루고 있습니다. 원점과 떨어진 거리는 $a_2$입니다. $x$좌표는 $\cos$함수를 이용해 구할 수 있습니다. $\cos{ 45^\circ } = x / a_2$이고, $x = \cos{ 45^\circ } \times a_2$가 됩니다. $y$좌표는 $\sin$함수를 이용해 구할 수 있습니다. $\sin{ 45^\circ } = y / a_2$이고, $y = \sin{ 45^\circ } \times a_2$ 입니다.

모든 꼭짓점의 좌표를 구해보면 다음과 같습니다.

  1. $(0, a_1)$
  2. $(\cos{ 45^\circ } \times a_2, \sin{ 45^\circ } \times a_2)$
  3. $(a_3, 0)$
  4. $(\cos{ 45^\circ } \times a_4, -\sin{ 45^\circ } \times a_4)$
  5. $(0, -a_5)$
  6. $(-\cos{ 45^\circ } \times a_6, -\sin{ 45^\circ } \times a_6)$
  7. $(-a_7, 0)$
  8. $(-\cos{ 45^\circ } \times a_8, \sin{ 45^\circ } \times a_8)$

모든 꼭짓점의 좌표를 구했으면, 이제 볼록 다각형인지 확인해야 합니다. 볼록 다각형은 연속하는 세 꼭짓점이 시계 방향을 이루어야 합니다. 시계 방향을 이루고 있는지 알아보기 위해 CCW를 이용할 수 있습니다.

능력치를 배열하는 방법의 수는 $O(N!)$가지이고, 배열할 때마다 볼록 다각형인지 검사하는 과정은 $O(N)$입니다. 총 $O(N! \times N)$에 해결할 수 있습니다.

소스 8

$\cos{ 45^\circ }$와 $\sin{ 45^\circ }$ 의 값은 같기 때문에, 소스 코드에서는 $\cos{ 45^\circ }$를 cos45에 저장하고, 두 경우 모두 이 변수를 이용했습니다.

모든 꼭짓점의 좌표는 $a + b \sqrt{ 2 }$의 형태를 가지기 때문에, 이를 관리하는 클래스를 만들면 실수 자료형을 사용하지 않고도 소스 9와 같이 해결할 수 있습니다.

소스 9