[PS] 2021 SNUPC Division 2

SangHyun Yi·2022년 2월 2일
0

시작하기 전에...

이번에는 서울대학교에서 2021년 개최한 프로그래밍 경시대회 기출문제를 풀어보았다. Division 1과 2로 구분되어 있길래 난이도를 확인해보니 1은 문제부터가 감히 손도 못댈 것처럼 무시무시해보였고, 2는 그나마 풀어볼만 한 것 같아서 한 번 시도해보았다.

문제는 A~I까지 총 9문제로 구성되어있으며, 원래는 9문제를 다 풀고 글을 쓰려고 했으나 마지막 H, I 2문제가 너무 오래걸릴 것 같아서 푼 7문제부터 정리해서 올리려고 한다.

문제 풀이

A. 23037: 5의 수난

[링크] 단순한 구현 문제였다. cmath 헤더의 pow 함수를 사용했다.

B. 23038: 박스 그림 문자

[링크] 역시 단순한 문제였다. i+ji+j가 홀수 일 때만 채우면 되기 때문에 상, 하, 좌, 우 모양이 채워져 있고 따라서 빈 칸의 모양이 유일하게 결정된다.
좀 더 고민했으면 훨씬 깔끔하게 짤 수 있었을 것도 같지만 우선 직관적으로 해결했다.

C. 23039: 실 전화기

[링크] 처음에 살짝 헤맸던 문제다. 뭔가 일반화 할 수 있을 것이라 생각하고 토끼가 3마리일 때부터 규칙성을 찾으려고 했는데, 그럴 필요 없이 토끼를 5마리로 고정하고 단순히 충돌이 몇개 생기는지만 확인하면 되는 문제였다.

실의 충돌이 1~4개 있을 때는 모두 하나의 토끼에서 나온 줄이 충돌한 것으로 볼 수 있고, 다행히 어떤 경우에서도 그 토끼만을 옮겨서 충돌을 없앨 수 있다.
문제는 충돌이 5개 있을 때인데, 완전그래프인 경우 절대로 충돌을 피할 수 없지만, 그렇지 않은 경우는 2개의 토끼를 옮겨서 해결할 수 있기 때문에 그 부분도 코드에 추가해주었다.

D. 23040: 누텔라 트리(Easy)

[링크] 그래프 문제를 안 풀었던 걸 후회하게 만들어준 문제였다. 막상 해설을 보고 곰곰이 생각해보니 생각 못할 것도 아니었는데, 지레 겁먹고 계속 어렵게만 생각했던 것 같다.

처음에는 DFS로 풀려고 했었다. 검은색 Node부터 시작해서 빨간색 노드를 탐색해나가며 count를 1씩 늘려가면 답이 바로 나오기 때문이다. 하지만 이렇게 풀 경우 검은색 노드가 많아졌을 때 걸리는 시간이 점점 늘어나고, 시간초과가 나게 된다.

그렇다면 어떻게 접근해야 할까? 출발하는 검은색 노드가 바뀌더라도 (검은색 노드가 없는) 연결된 빨간색 노드들의 집합은 변하지 않는다. 또한, 결국 누텔라 경로의 갯수는 그 집합의 빨간색 노드의 개수와 같기 때문에 메모이제이션을 이용해서 미리 계산해놓으면 시간초과를 막을 수 있다.

여러가지 방법으로 구현할 수 있겠지만, 나는 스택을 이용해서 해결했다.

E. 23041: 뛰는 기물

[링크] 이 문제도 굉장히 흥미로운 문제였다. 처음에는 "(N,M)(N,M)-기물을 이용해서 (0,0)(0,0)에서 (p,0)(p,0)을 갈 수 있는가?" 에 관해서만 주목했었다. 그래서 p=gcd(n+m,nm)p = gcd(n+m, n-m)일 때 p2p^2를 답으로 내려고 했었는데, 생각해보니 (1,1)(1,1)로 갈 수 있는 기물의 경우 답이 22가 될 수 있었다. 그래서 gcd(n,m)gcd(n,m)으로 p2/2p^2/2가 나누어떨어질 경우에는 p2/2p^2/2을 답으로 내놓게 하였고, 정답을 맞힐 수 있었다.

하지만 이렇게 풀고 보니, 뭔가 수학적으로 증명할 수도 없고 찜찜한 마음이 들어 SNUPC 2021 공식해설 유튜브를 확인해보니 엄청난 일반화로 풀 수 있다는 사실을 알게 되었다... 이 부분에 대해서는 나중에 한 번 더 짚고 넘어가야 할 것 같다.

결국에는 운이 좋아서 맞췄던 걸로ㅠㅠ

F. 23042: AND와 OR

[링크] 이런 문제는 어떻게 생각하는건지 참 대단하다는 생각이 들었다. 이 문제에서 가장 중요한건

두 수를 고르고, 이 두 수를 두 수와 bitwise AND 및 bitwise OR가 모두 같은 두 음이 아닌 정수로 바꿉니다.

이 문장이었다. 그러면 다음과 같은 사실을 알 수 있는데,

  1. AND와 OR이 같은 두 정수라고 한다면 두 정수의 이진법 상 같은 자리를 차지하는 비트가 다를 때 그 순서를 바꾸는 연산이라고 볼 수 있다.
  2. 두 양수 a,b(a>b)a, b (a>b)가 있을때, aa보다 작은 임의의 양수 cc에 대하여 ab>(a+c)(bc)ab > (a+c)(b-c)임은 쉽게 증명 가능하다. 따라서 어떠한 연산을 하든지 주어진 수들의 곱을 최소화한다면 큰 수를 더 크게, 작은 수를 더 작게 만들어야 한다는 사실을 알 수 있다.

위의 두 사실로 부터, 문제에서 주어진 NN개의 정수들의 이진법의 각 자릿수 별로 1의 개수를 센 뒤, 가장 큰 수부터 차례로 그 1을 넣어주면 해결할 수 있는 문제였다.

G. 23048: 자연수 색칠하기

[링크] 단순히 소수의 개수를 찾는 문제와 다를게 없다. 다만 소수 판별을 하다가 나누어 떨어지는 수가 발견되면 그 수와 같은 색으로 칠해주는 코드를 추가해주어야했다.

코드

위 문제를 푼 코드는 Github에 올려두었다.
https://github.com/brighthonor/PS/tree/master/SNUCP/2021_Div2

정리

몇 문제들은 자신있게 풀 수 있었지만, D나 E같은 문제들은 시간도 오래걸렸을 뿐만 아니라 수학적으로도 완벽히 증명하지 못하고 푼 것 같아 아쉬웠다. 그래프나 정수론 관련 문제들을 좀 더 많이 풀어서 익숙해져야 될 것 같다.

또, 글을 쓰면서 느낀거지만 내가 아는 것과 남에게 설명하는 것은 정말 큰 차이가 있다는 사실을 다시 한 번 깨달았다. 나름 열심히 설명한다고 쓴건데, 읽는 입장에서는 전혀 이해가 안 될 것 같아서 걱정이다. 지금부터라도 이해된 내용을 설명하는 연습을 계속 해나가야 할 것 같다.

profile
Algorithm, AI, Full Stack Development, AWS, Computer Science

0개의 댓글

관련 채용 정보