SUAPC 2등!!
사실 팀 목표는 1등이였고, 가능성도 꽤 높았다고 생각했는데 이런저런 아쉽게 됐다. 이 셋 기준으로는 아무리 잘했어도 10솔 하기는 힘들었을 것 같다. 1등팀이 굉장히 잘했다. ㄷㄷ
피드백 할만 한 문제들만 몇개 정리한다.
C. 점수 내기
A와 B가 게임을 합니다. A는 조건을 만족하는 최대 점수 문자열을, B는 조건을 만족하는 최소 점수 문자열을 만들려고 합니다. 다음 조건에서 A와 B가 최선을 다했을 때 받을 수 있는 점수를 출력해주세요. (A와 B가 만드는 문자열은 알파벳 소문자와 숫자를 이용할 수 있습니다.)
조건 : 만든 문자열 S에 대해, '접두사 목록'에 존재하는 문자열 S의 접두사들의 점수를 모두 더합니다. '접미사 목록'에 존재하는 문자열S의 접미사들의 점수를 모두 더합니다.
총 q(3e5)개의 쿼리에 대해, 다음 4 종류의 쿼리가 주어집니다. 주어지는 쿼리의 문자열 길이의 총합은 1e6을 넘지 않습니다.
쿼리 1 : 접두사 목록에 문자열 T와 점수 x를 추가합니다. (T는 알파벳 소문자만으로 이루어져 있습니다.)
쿼리 2 : 접미사 목록에 문자열 T와 점수 x를 추가합니다. (T는 알파벳 소문자만으로 이루어져 있습니다.)
쿼리 3 : A가 만들수 있는 최대 점수를 출력합니다.
쿼리 4 : B가 만들수 있는 최소 점수를 출력합니다.
풀이는 다음과 같다.
1. 접두사 목록과 접미사 목록을 분리해서 생각할 수 있다. 예를 들어 접두사 목록 abc와 접미사 목록 ba를 쓴다고 할 때, 반드시 abc0ba와 같이 가운데에 숫자로 벽을 칠 경우 모든 예외를 막을 수 있다.
2. 접두사 목록에서 최대 점수/최소 점수 접두사를 판단하기 위해 트라이 + lazy로 관리할 수 있다. 자세한 관리방법은 다음과 같다.
2 - a. 트라이에 꼭 필요한 정보 : max, min, num, lazy
2 - a. 트라이에 새로운 노드가 입력된다. -> 그냥 큰 문제 없이 이전 노드의 num을 가져와 갱신해주면 된다.
2 - b. 트라이에 기존의 노드가 입력된다. -> max, min, num에 모두 x만큼 갱신한다. lazy를 이용해 자신의 아랫 노드에 전부 뿌려주며, 동시에 자신의 parent들의 max, min을 갱신한다.
10틀... 10틀.......
이 문제에 한이 엄청 쌓였다....
풀이는 거의 바로 찾았지만, 트라이도 처음 써봤고 거기에 익숙치 않은 lazy비빔밥이 얹혀지면서 제대로 폭망했다. 처음 코드에서 고칠게 이중 삼중 사중으로 있었다.(...) 마지막까지 틀렸지만 사실 마지막에 제출한 코드에서 한 줄만 고쳤다면 정답코드였다. 그것은 바로 lazy를 갱신해줄때 lazy값을 0으로 비워주는것... 실화냐..
디버깅에 대해서도 고민을 많이 하게 됐다. 예전에는 반례를 무지성으로 찾아내면서 디버깅하는것을 선호했는데, 그냥 코드를 열심히 읽는 편이 훨 나을 것 같다. 코드 읽는 실력도 예전보다 훨씬훨씬 늘었고 걍 코드만 3번 읽었으면 오류를 다 찾았을 것 같다. 2시간동안 뭘 한건지 모르겠다..
E. 슬라이딩 퍼즐 마스터
N * M (N * M ≤ 9) 보드판이 있습니다. 여기에는 1 ~ (N * M - 1)까지의 숫자와, 빈 칸 하나가 주어집니다. 다음 두 가지 연산중 하나만을 이용해, 모든 상태를 중복 없이 전부 나타내세요.
연산 1) 빈 칸에 인접한 숫자를 이동시킵니다.
연산 2) 인접한 숫자 두개를 서로 바꿔치기합니다.
풀이는 다음과 같다.
1. 사실 빈 칸은 숫자와 동일시 해도 상관 없다.
2. 2차원 배열처럼 보이지만, 사실 스네이크 형식으로 본다면 1차원 배열과 똑같다. 즉, 1차원 배열 9개의 9! 상태를 바로 인접한 숫자와 swap해서 모든 상태를 한번씩 이동하는 문제가 된다.
3. 길이가 n인 순열을 관찰해보면, 가장 앞 숫자 a를 골라 a를 가장 오른쪽으로 보내보자. 그러면 a를 제외한 (n - 1)길이의 순열에 대해 길이가 n인 순열에서 나올 수 있는 모든 상황이 기록된다. 이를 바탕으로 a를 계속 좌우 끝과 끝으로 이동시켜 가며 (n - 1)길이의 순열에 대해 재귀적으로 반복하는 방식으로 풀 수 있다. (Steinhaus–Johnson–Trotter Algorithm)
이 문제는 다음 두 가지 이유로 난이도가 굉장히 높다.
1) 풀이 2, 3번의 관찰이 어렵다. (특히 3번)
2) 풀이 3번에 해당하는 재귀함수가 구현이 상당히 까다롭다. (본인은 역순으로 구현을 했는데, 정답자 코드를 읽어보니 vector<int>를 인자로 받아 n = 9에서 재귀로 구현하던데 그 편이 한참은 쉬울 것 같다..)
이 문제는 돌아가도 풀기 어려웠을 것 같다. 풀이 2 관찰까지는 금방 했던 편이였는데, 풀이 3 관찰은 아무리 생각해봐도 난이도가 너무 너무 높다.. 이 문제는 구현 난이도도 상당하다.
이런 유형의 문제를 풀기 위해서는 순열의 특징에 관해 깊게 공부해봐야 할 것 같다. 최근 AGC 61 A에서도 비슷한 문제가 나와 크게 데였다. 그 문제는 짝수 길이의 순열에서만 생기는 인접한 원소끼리의 특징을 바탕으로 했다. 이 문제는 원소를 하나 쭉 돌아갈 때 나머지 순열의 위치를 관찰하라는데.. 솔직히 발상 난이도가 지나칠 정도로 높다. 어떻게 발상하는건지 아직도 이해가 안간다.
I. UFO in Sinchon
N(1e9) * M(1e9) 짜리 격자에서 K(2e5)명의 사람이 있고 Q(2e5)번 순서대로 UFO가 나타납니다.
K명의 사람은 UFO가 나타날 때마다 매 턴 택시거리로 가장 가까워지도록 가로, 세로, 대각선 8방향 중 한 방향으로 이동합니다. UFO와 같은 위치에 있다면 이동하지 않습니다.
UFO는 (x, y, t) 형태로 나타나며 (x, y)위치에 나타나 t(1e9)턴 후 사라집니다.
K명의 최종 위치를 모두 구해주세요.
풀이는 다음과 같다.
1. x와 y는 분리해서 생각해도 된다. 즉, 1차원에서 현재 위치가 a, 우주선이 (x, t)형태로 주어질 때 q번의 ufo가 나타나고 갈 위치를 잘 관리하는 문제로 변한다.
2. 우주선이 (x, t)로 나타나면, (x - t)보다 작은 경우 a + t, (x - t ~ x + t)의 경우 x, (x + t)보다 큰 경우 a - t의 위치로 최종 이동한다.
3. 이 정보를 바탕으로 lazy segment tree에 y = ax + b(순서대로 (a = 1, b = t), (a = 0, b = x), (a = 1, b = -t))를 잘 관리해 갱신한다.
이건 접근 1은 내가 했지만 2, 3번은 다른 팀원이 했다. 사실 2~3은 처음 보는 유형이였어서 시간을 들였어도 쉽게 풀지는 못했을 것 같다.
추가 예정
L. 따로 걸어가기
N(2e5)행 M(2e5)열의 2차원 격자가 있습니다. 두 행인 A, B에 대해, 다음 경우의 수를 구하세요.
- A, B가 1행 1열에서 N행 M열까지 오른쪽, 혹은 아랫쪽 방향으로 한칸씩으로만 이동해 도착할 때, 둘이 시작점과 끝점을 제외한 모든 점에서 마주치지 않는 가짓수
풀이는 다음과 같다.
1. 두명의 이동은 결국 오른쪽과 아래중 하나의 경로를 동시에 택하는 선택과정의 연속이라고 볼 수 있다. (두 명의 경로를 따로 보지 않고, 두명이 동시에 이동한다고 보자.)
2. 이동방식은 4가지밖에 없고, 특징을 잘 살펴보면 그 안에서도 규칙이 발생한다. 규칙은 다음과 같다.
2 - 1. 이동 방식은 (D, D), (D, R), (R, D), (R, R) 밖에 없다. ( (R, D)는 1번 사람이 오른쪽으로, 2번 사람이 아래로 이동한다는 뜻이다.) 이 이동방식을 순서대로 이동1, 이동2, 이동3, 이동4라고 하자.
2 - 2. 1, 2번 사람은 둘 다 D를 총 n번, R을 총 m번씩 이동해야 하기 때문에 이동횟수 간의 연립식이 생긴다. 정리하면 이동1이 k회 이동했을 때, 이동2 = 이동3 = n - k번, 이동4 = m - n + k번 이동하게 된다.
2 - 3. 일반성을 잃지 않고 n ≥ m이며 1번 사람은 처음에 D로, 2번 사람은 처음에 R로 이동했다고 치자. (n < m인 경우에는 n, m을 바꿔주면 되고, 1번 사람과 2번 사람이 반대로 이동한 경우는 정확히 횟수가 똑같기 때문에 최종 답에서 2배 해주면 된다.) 그러면 항상 이동2 횟수 ≥ 이동3 횟수를 유지해야 하기 때문에 (이동2, 이동3)은 올바른 괄호쌍을 만드는 카탈란 수로 표현해줄 수 있다.
2 - 4. 1번 이동 각 가능한 k에 대해, 전체 이동에서 이동1의 위치, 이동4의 위치, (이동 2 + 이동 3)의 위치를 선정하는 가짓수 * 이동2와 이동3을 적절히 배치하는 카탈란수 가짓수를 정리하면 O(n)에 총 가짓수가 나온다.
나는 대회때 한 10분정도 보고 포기한 문제인데, 나중에 풀어보고 난 후 난이도는 생각했던 것보다는 쉬웠다. 접근 1이 생소한 것 같고, 접근 1을 올바르게 했다면 뒷부분은 대회때 풀었을 것 같다.
접근 1은 완전히 처음 보는 유형인데, '두 명이 서로 다르게 이동한 경로' 라는 키워드에서 생각해볼 수 있을법한 좋은 접근인 것 같다. 항상 총 가짓수 구하는 유형에 약하다. 이쪽 유형도 많이 공부해야겠다는 생각이 자주 든다.
'PS 개인 공부 > 대회 후기' 카테고리의 다른 글
2024 SUAPC summer 후기 (5) | 2024.09.03 |
---|---|
2024 UCPC 후기 (2) | 2024.08.06 |
2024 ICPC Asia Pacific Championship 후기 (0) | 2024.03.24 |
SCPC 2023 본선 후기 (1) | 2023.09.24 |
현대모비스 2023 본선 후기 (1) | 2023.09.24 |