18시쯤 대전역에 도착하는 ktx를 타고 대전으로 이동했습니다. 제 기억으로 대전은 처음 방문합니다. 새벽2시에기하를하다니이상해는 자차를 가지고 왔고 대전역에서 합류했습니다. 팀원이 전부 토요일부터 대전에 있기 때문에 같이 저녁을 먹고 가기로 했었기 때문에 함께 카이스트에 있는 새벽2시에구현을하다니이상해를 만나러 갔습니다.

저녁을 먹고 인근 카페에서 환경 세팅을 했습니다. 상대적으로 세팅이 귀찮은 C/C++가 세팅되어 있는 제 랩탑을 사용하기로 했고, 여러 우여곡절이 있긴 했으나 pycharm을 설치하는 것으로 세팅을 완료했습니다. 우선 제 랩탑이 16인치 4k 100% 10pt수준으로 세팅되어있어서 해상도를 자연스럽게 유지하는 것이 꽤 어려웠고 아마 대회시점까지도 보기 막 좋지는 않았던 것 같습니다.

카이스트 기숙사로 들어와서 Gomori-Hu를 주제로 쓰던 블로그 글을 마무리하려고 했는데 돌연 wjdgud0621님이 모은 마작 파티에 가서 한게임 했습니다. 같이 마작을 한 LLMalreadyallsolved팀의 방에 갔습니다. kolorvxl이 와도 된다고 했는데 alreadysolved님은 전혀 모르는 눈치였습니다. LLM과 제 방으로 돌아갔다가 운영진이었던 hibye1217이 다시 습격해왔습니다. 잠시 나갔다 싶더니 rlatjwls2000kolorvxl을 데리고 3인 레이드를 해왔습니다. 결국 블로그 글은 못썼습니다.

다음날 5시쯤 일어나서 씻고 준비를 했지만 다시 잠들어버렸고 9시가 돼서 일어났습니다. 새벽2시에기하를하다니이상해가 10시쯤 도착한다고 해서 여러 부스를 돌아다니며 인사했습니다. 등록 테이블은 바쁠 듯해 부스에서 도장을 찍어주시던 man_of_learing과 인사를했습니다. 친절하게 등록하면 도장을 찍을 수 있는 팜플릿을 준다고 알려주셨습니다. 먼저 도착해있던 새벽2시에구현을하다니이상해와 만나 준비된 다과와 함께 전략에 대해 잠깐 얘기했습니다. 등록 티셔츠를 배부하시던 queued_q님을 찾아가서 인사하고 재미있는 퍼즐을 몇개 보면서 재밌게 기다렸습니다. 도장을 찍어주시는 분들 중에 낯익은 이름이 있길래 cubic님도 찾아가서 인사했습니다. 온라인에사는 자주 대화했지만 오프라인에서 처음 보는 상태였으나 서로 일방적으로 알고있었습니다. 사진 부스에 있던 dadas와 전체적으로 사진을 찍으시던 leejseo님을 찾아가서 간단한 농담을 하기도 했습니다. 새벽2시에기하를하다니이상해가 도착하고 나서 등록 데스크에 있는 hibye1217를 통해 등록했습니다. 별도로 팀명을 얘기하지 않았는데 신분증만 간단히 확인하고 나서 등록이 완료됐습니다. 가방을 대회장에 들여놓고 부스를 돌며 스탬프를 받아 튀김소보로를 받았습니다. 상태가 나쁘진 않았던 것 같으나 팥앙금을 별로 좋아하는 편이 아니라 다소 힘들긴 했습니다.

튀김소보로를 들고 경희대학교 팀에 가서 같이 얘기했습니다. 2025 ucpc에 같은 팀으로 나갔던 overnap과는 오프라인에서 처음 보는 사이였으나 나머지 두 팀원은 아니었기에 쉽게 특정할 수 있었습니다. 2025 ucpc에 저를 제외한 두 팀원은 서로 면식이 있었기 때문에 작년에 같이 왔어야 되는데라는 말 정도로 알아보셨습니다. 대회장에서 대전역 대 전역 팀의 kwoncycle이 보여준 tourist의 진품 사인을 구경했습니다. 여러 팀을 돌아다녀보고싶었지만 다들 바쁘신 듯했습니다.

대회가 5분 딜레이됐습니다. 대회 시뮬레이션이 덜 된게 아닌가 싶긴 했으나 딜레이정도는 충분히 있을 수 있는 일이기 때문에 큰 문제는 없었습니다. fefe 회장님이 5분 추가 딜레이를 요청했으나 딜레이하기 전에 지문이 공개돼버렸기 때문에 갑자기 시작하게 됐습니다. 대회 오프닝을 준비했는지는 모르지만 했다면 아쉽게된 상황입니다.

 

시작하기 전 팀 전략을 조금 얘기하고 갔습니다. 전략대로 새벽2시에기하를하다니이상해가 A부터 읽고 저와 새벽2시에구현을하다니이상해가 뒤에서부터 일찍 읽는 순서대로 하나씩 가져가서 읽기로 했습니다. 쉬운 문제가 나오면 새벽2시에기하를하다니이상해에게 넘겨 노솔브 방지 문제를 우선 해결하고 시작하기로 했습니다.

이하는 팀 내에서 100% 주관적인 관점으로 흐름을 간단히 요약한 것입니다.

 

L(00:16) 제가 처음 읽었습니다. 간단히 훑어보니 상태가 많아야 9가지인 dp식이 나왔습니다. 제가 구현하는 것보다 새벽2시에기하를하다니이상해가 파이썬으로 구현하는게 빠를 것 같아 구현을 토스했습니다. 무난하게 해결했습니다.


C(01:09, +1) 다들 헤멨습니다. 스코어보드를 보고 BCD가 다음 할만한 문제라고 판단은 했으나 셋 중 뭘 먼저 봐야할 지 고민을 했습니다. 새벽2시에기하를하다니이상해가 B를 읽고 11의 배수 판정을 물어봤습니다. 제가 B의 풀이가 대략적으로 보여서 손으로 계산하는 사이 팀원 둘이서 C의 풀이를 찾은 듯했습니다. 홀수번째 짝수번째로 나눈 뒤 교대합에 따라 각 자릿수가 무엇이어야했는지 추적하는 손계산을 했습니다.

 

N(02:13,+1) 제가 I의 대략적인 풀이를 가지고 구현을 한참 하고 있었습니다. 새벽2시에기하를하다니이상해가 N을 읽더니 전날 팀 연습문제로 푼 아이디어를 이용해서 해결할 수 있다고 하는게 들렸습니다. 제가 생각했던 I의 풀이가 세제곱 스케일임을 깨닫고 N으로 머신을 넘겼습니다. 답은 옳게 나오지만 느린 풀이였습니다. 새벽2시에구현을하다니이상해에게 풀이를 설명하고 간선 개수를 제곱 스케일로 줄일 방법을 함께 고민했습니다. 이분 매칭 구현으로 호프크로프트 카프를 이용했기 때문에 exchange로 간선 개수를 제곱 스케일로 줄이면 돌 것 같았지만 10년전 분단의 슬픔 문제처럼 디닉이 정해인 문제인가 싶은 생각도 있어서 회의적이라고 생각하기도 했습니다. 결국 I를 풀지 못했습니다.


B(02:21,+6) B의 거의 대부분의 풀이를 정리했습니다. 혼자 정리한건 아니고 새벽2시에기하를하다니이상해가 구현하면서 같이 정리했습니다. 구현에 실수가 있었지만 우여곡절 끝에 AC를 받았습니다. 이 글을 쓰면서 에디토리얼을 읽어 보니 생각보다 간단한 구현이 있었습니다. 추가로 디버깅하면서 여러 입력을 집어넣어봤는데, 생각보다 sparse해서 런타임 전의 전처리를 할 수 있지 않을까싶었습니다. a와 b가 대수적으로 어떤 관계가 있어야 할 것이라는 추측은 했으나 끝까지 합이 9여야한다는 것을 정리하진 않았고 런타임에 처리했습니다.

 

M(03:53,+1) 3:00이 되기 전 즈음에 D의 풀이를 발견했습니다. 열심히 구현했고 계속 예제가 틀리게 나왔습니다. 처음 구현에 lazy segtree를 썼지만 계속 예제가 틀리게 나와 식을 정리하다가 쿼리가 업데이트보다 항상 느림을 깨닫고 차분 배열을 이용한 구간 업데이트 구현으로 틀었습니다. 핵심 관찰은 동일하지만 방식이 출제진 예상 풀이는 아니었다고 들었습니다. 계속 구현에 애를 먹었습니다. 손으로 예제를 계산하고 쿼리를 디버깅 찍어보고 별 짓을 다 해봤지만 예제가 잘 안나왔습니다. 그사이 새벽2시에기하를하다니이상해가 M의 풀이를 발견했습니다. 어차피 할 일이 디버깅 뿐이었어서 출력 요청을 하고 머신을 넘겼습니다. 대회장 사정때문에 출력이 안 온것만 제외하면 할 수 있는 만큼 다 해본 듯합니다. 

 

D(03:55) 크리티컬한 오타 하나를 발견하고 AC를 받았습니다.

 

F(-1) 새벽2시에구현을하다니이상해가 casework 풀이를 냈습니다. 무슨 내용인지는 모릅니다. 어차피 패널티로 승부를 볼 수는 없는 상태였기 때문에 일단 구현해서 제출하고 크리티컬한 반례를 찾은 듯 했습니다.

G(-16) 한시간여 남은 시간에 새벽2시에기하를하다니이상해가 G의 풀이 정리를 마쳤습니다. 열심히 구현했고 파이썬으로 구현한 것이 문제였는지 시간초과를 계속 받았습니다. 파이썬이 아니었다면 7솔브를 하고 25위로 올라갔을지 모른다고 생각했습니다.

K(0) 마지막까지 변수 K의 제한을 이해하지 못했습니다. 대신 K에 의존하지 않는 리차오 트리 풀이 $O(Qlg^2T)$를 내고 시간내에 구현할 수 없다고 판단해 포기했습니다.

J(0) 누가봐도 LCP를 쓸 것 같았습니다. 핵심 관찰을 하지 못해 해결하지는 못했습니다. 

H(0) 새벽2시에구현을하다니이상해가 설명해주고 거의 완벽한 풀이를 가져왔습니다. 제가 구현하려고 casework를 열심히 나눴는데 단계 수가 너무 많아 끝까지 정리를 못했습니다. 하나를 셔플하고 그리디하게 주는 방법과 둘 다 셔플하는 방식이 있었는데 후자를 선택하려 했으나 증명도 못하고 구현을 위한 식 정리도 못하고 난장판이었습니다.

E(0) 끝까지 읽어보지 못했습니다. 새벽2시에구현을하다니이상해가 이상한 수학 문제라고 버렸다고 했는데 이상한 수학 문제를 풀어 만회라고 해야겠다고 생각한 제가 그걸 못봤습니다. 

 

새벽2시에기하를하다니이상해는 월요일 출근이 있다고 한걸로 기억합니다. 그래서 대회가 끝나자 마자 복귀할 계획을 하고 있었는데 혹시 모르는 특별상을 위해 스코어보드 공개까지 남아있었습니다.

스코어보드가 공개되면서 ucpc 특별상을 수상하게 됐습니다. 스코어보드를 오픈하시던 fefe 회장님이 진짜 울릉도에서 연습했냐고 물어보셨고 그랬다고 제가 거짓으로 답했습니다. 재밌었으면 됐던게 아닐까 싶습니다. 실제로 장마 예보로 인해 결항이 되면 불참할 위험이 있었고 개인 일정도 있었기 때문에 연습하지 못했습니다. 다들 진짜 했냐고 물어봤지만 언제, 누가, 무슨 본선을 가면 연습한다고 한 적 없다고 답해드렸습니다. 추가로 다른 특별상 상품들이 각자 재밌는 상품이 많아서 좋았습니다. 제가 받으면 더 좋았을 것 같습니다. 내년에 참가하게 된다면 제 상품도 준비해주세요.

Janestreet gamenight에 참가하기 위해 새벽2시에구현을하다니이상해와 버스를 타고 이동했습니다. 이때 새벽2시에기하를하다니이상해는 서울로 돌아갔습니다. 장소에 도착하고 엘리베이터를 타고 올라가라고 안내해주셨는데 몇층으로 가라는 말이 없어서 엘리베이터에 함께 타신 참가자들과 협동해서 브루트포스를 했습니다.

연회장에 도착해서 가장 앞쪽의 스크린 아래에 앉았습니다. 같은 테이블에 숭실대 팀이 같이 앉았으나 멀어서 큰 대화를 하진 못했습니다. 경희대학교 팀이 뒤에 들어오는 것을 보고 같이 앉자고 했습니다. 식사는 적당히 먹었습니다. 식사를 적당히 먹고 PULSE 회원들과 함께 사진도 찍었습니다. 사진을 찍고 난 뒤 queued_q님의 비공식 퍼즐해결부스에서 재밌게 즐겼습니다. 스태프 분들이 식사하시는 자리에 JustHui님과 man_of_learning님이 옆에 앉으라고 하셔서 사이에 끼어 앉아서 퍼즐을 해결했습니다. man_of_learning님이 queued_q님한테 가서 스탬프를 받으라고 재미있게 말씀해주셔서 queued_q님이 앉아계신 테이블에 가서 스탬프를 받았습니다. 테이블에 펼쳐두신 다른 퍼즐도 맞추면서 지나갔습니다.

적당히 퍼즐을 풀고 나서 자리로 돌아가는 길에 ALOHA 회원들이 있는 테이블에서 hibye1217이 불렀던거같은데 아무튼 그렇게 앉아서 얘기했습니다. 다른 분들은 대충 면식이 있었지만 한분이 면식이 없어 어색하게 말을 걸지 못했는데 집에 돌아가는 길에 Arpia님인걸 깨달았습니다. 크게 중요한 얘기는 안했지만 늘 있는 WWE를 많이 얘기했던 것 같습니다. 중간에 지나가는 koi312500 등 몇명에게 와서 같이 앉으라고 했는데 lycoris2000이 왔다는 사실이 기억나서 같이 인사하러 갔습니다. 평소에 SCSC때문에선지 접점이 제법 있었지만 현실에서는 처음 봤는데 현실에서 제법 어색해하는 듯했습니다. 간단히 인사하자마자 복귀해야할 시간이 되어 koi312500cenix820과 버스를 타러 내려갔습니다. cenix820은 분명 PNUPC에서 봐서 면식이 있었는데 왜 자신을 모를거라고 생각했는지는 잘 모르겠습니다.

 

카이스트로 복귀하고 나서 pani가 1층에서 얘기중이라는 사실을 확인하고 인사하러 갔습니다. 둘이 얘기하던 중 overnap이 합류해서 2025년도의 CAPTCHA가 각각 쪼개져서 본선에서 모였습니다. CAPTCHA가 예비 2번이었는데 예비 1번까지 본선에 진출했다고 들었습니다. 아쉬웠던 생각이 한 번 더 나는 저녁을 보내게 됐습니다. 

 

주말 저녁에 복귀하기에는 시간이 빠듯하거나 해서 월요일 아침에 복귀하기로 했습니다. 월요일 세미나에 toycartoon이 온다고 해서 중간에 만나서 점심을 먹기로 했습니다. 대전에 살고 있는 koi312500과 중앙로에서 만나서 점심을 먹으러 갔습니다. 성심당 본점 근처에 있는 식당에서 점심을 먹고 koi312500의 도움을 받아 성심당 본점 대기시간을 어림해봤는데 볕에 기다리기 곤란해서 바로 대전역으로 향했습니다. 성심당 대전역점에 줄이 없어서 구경 차 들어갔다가 대여섯개를 포장해 나왔습니다.

 

대회 퍼포먼스는 좋지 않았습니다. ICPC나 다른 대회에를 돌아보면 공통적으로 제가 긴장하면 안그래도 못하는 카운팅을 더 못하게 되는 듯합니다. 긴장을 풀만한 방법을 찾아야 할 듯합니다. 특히나 다른 팀의 풍선이 늘어날수록 불안감이 커지는 현상이 있었는데, 스스로 멘탈 관리를 하는 법을 익혀야겠습니다. 이밖에도 경험이 부족해서 관찰하지 못한 포인트나 그냥 못해서 관찰하지 못한 포인트가 눈에 밟힙니다. 결국 문제를 많이 풀어야 한다는 것이 결론입니다. 추가로 구현에 잦은 실수가 있었는데, 예제까지 손계산해보고 예제가 안나오면 템플릿이 틀린게 아닌가 봐야한다는 점을 깨달았습니다. G를 C/C++로 구현해서 맞거나 H를 틀리지 않고 구현해서 맞았거나 K의 관찰을 해서 쉬운 구현을 해서 맞았거나 셋 중 둘만 됐으면 8솔브였으리라 생각을 해보지만 딱히 도움되는 생각은 아닌 듯합니다. 업솔빙을 해서 만약 내년이 있다면 내년 대회나 적어도 이번 ICPC에서는 좋은 성적을 거둬보는 것을 목표로 해야겠습니다.

후기를 쓰다 보니 ICPC 25-26 APAC 후기를 안썼다는 것을 깨닫고 쓰고 나니 후기가 날아가서 포기하고 다시 돌아와서 씁니다. 저장하기를 생활화해야겠습니다. APAC 후기는 무기한으로 미루기로 했습니다.

 

UCPC 2026에 본선가면울릉도에서팀연습새벽2시에DP를하다니이상해라는 이름으로 출전했습니다.

 

새벽2시에DP를하다니이상해: 아는 자료구조가 많으나 지식에 비해 활용도가 낮습니다. EDPC를 전부 풀며 활용법에 대한 감을 키우긴 했으나 조금 부족합니다. 구현을 쉽게 저는 편이지만 그럼에도 불구하고 문제를 풀기 위해 공부해둔 잘 짜여진 템플릿을 제법 외우고 있습니다. 긴 구현이나 애드혹한 구현에 약하고 카운팅이나 off by one을 어려워하지만 usual한 구현이나 아이디어를 내는데 강점이 있습니다.

새벽2시에기하를하다니이상해: 기하를 잘합니다. 비슷한 의미로 흔히 차력쇼라고 하는 구현에 강점이 있습니다. 주력 언어가 파이썬이고 셋 중 짧은 구현이 가장 빠릅니다. 

새벽2시에구현을하다니이상해: 비슷하게 기하를 잘하지만 기하보다는 올라운더에 가깝습니다.

 

사실 팀 전력을 잘 알지 못합니다. 대충 서로 차력쇼를 하듯 비비다가 폭탄돌리기마냥 던지면 누군가 푸는 그런 팀 조합인 듯합니다.

 

가장 먼저 팀을 결성한건 DP/구현입니다. UCPC 콜포태를 받을 때부터 떨어지면 팀을 하자고 지나가듯 얘기했는데 둘다 까먹지 않고 팀이 됐습니다. 동시에 같은 처지인 기하와 팀을 만들었습니다. 

 

구현이 예선이 있는 주에 해외 일정이 있고 특히 예선 당일인 토요일에 귀국을 하는 일정이었기 때문에 조기퇴실해야 했습니다. 

 

대회 직전 화요일에 UCPC 2021 예비소집 연습 셋을 DP/기하가 돌았습니다. P21J의 센트로이드 분할정복 풀이를 거의 완벽하게 떠올렸지만 구현 디테일에서 몇가지 빼먹는걸 보고 제법 불안했습니다. 기하도 누적합에서 실수가 있었기 때문에 더 그랬습니다마는 그럼에도 불구하고 성적이 아주 나쁘지는 않아 한편으로 안심되기도 했습니다.

 

예비소집 입장이 13시부터였고 구현이 13시에 도착하지 못할 것이라고 미리 얘기했습니다. 13시에 디스코드에 도착하니 기하가 이미 도착해있었습니다. 둘이 먼저 전략에 대해 얘기하고 있었습니다. 기하가 쉬운 구현에서 저보다 빠르기 때문에 A를 빨리 밀고 균등하게 보면 되겠다고 했고, 제가 L부터 거꾸로 읽기로 했습니다. 13시 30분쯤 구현이 도착해 EF부터 읽기로 얘기하고 시작했습니다.

 

 

A(00:01, +0) 기하가 A를 아주 빠르게 해결했습니다. 나머지 둘은 문제를 읽지 못했습니다. 동시에 구현이 E/F/G를 읽고 제가 L/K/J를 간단히 훑어봤습니다. 

 

C/I(00:03) 구현이 C가 솔브가 나왔다는걸 빠르게 파악하고 기하가 구현에 들어갔습니다. 그때 저는 I를 읽고 간단한 패리티 조건분기 문제로 판단하고 간단한 구현에 들어갔습니다. 예선 전날 투스텝 문제에 대해 얘기를 좀 했는데, solved.ac 다이아 수준의 애드혹 문제가 나올 것이라고 예상했지만 실제 난이도는 그보다 더 낮았다고 합니다. 덕분에 투스텝에 대한 부담 없이 셋을 돌 수 있었습니다.

 

C(00:06, +0) 기하가 솔브했습니다. 마찬가지로 무슨 문제인지 읽지 못했습니다. 

 

D/I(00:07) 기하가 짧은 구현으로 해결할 수 있을거라고 했습니다. 그때 저는 I가 예제가 잘 나오지 않는다는 것을 깨달았습니다. 첫 관찰이 짝수번째 합과 홀수번째 합의 차가 일정하게 유지된다는 것이었는데 그것 이상의 다른 추가적인 관찰이 보이지 않아 포기하고 솔브가 나온 E를 읽었습니다. 구현이 다익스트라 같은 느낌이라고 해서 그래프 문제임을 어렴풋이 알고 시작했습니다. 한편으로 팀과의 소통에서 구현에게 I를 봐달라고 요청했습니다.

 

D/E(00:08) E번의 풀이를 어렴풋이 깨달았습니다. 문제를 읽으면서 그래프가 연결 그래프가 아니면 모두 연결될 수 없을지도 모르는데 하는 생각을 잠깐 하고 나니 모든 정점에 공항을 지으면 연결 그래프가 된다는 것을 알았고, 비슷한 시점에 MST가 떠올랐습니다. 같은 시각 기하가 D번의 풀이를 가져왔습니다. 다만 증명 없이 코드를 짰기 때문에 검토해야했습니다. 동시에 구현이 I의 그리디 풀이를 생각했습니다.

 

맞음

 

D/I(00:10) D의 검토를 하다 말고 솔브수가 많은 것을 보고 기하가 그대로 제출해서 맞았습니다. 이정도로 쉬운 문제가 아니라면 이 시간에 이렇게 많이 풀리기 어렵다는 계산이었습니다. 한편 구현은 I가 WA가 많이 쌓인 것을 보고 풀이를 재검토하기 시작했습니다. 기하구현이 동시에 검토하고 반례를 만들기 시작했습니다. 저는 음성 채팅으로 검토에 동참함과 동시에 E를 구현하고 있습니다. 

 

E/I(00:15) 이 시점에 E번이 MST를 두번 하도록 구현하는 것이 좋다는 판단을 했습니다. 동시에 I의 제한을 수상하게 여기고 구간 dp를 사용하는 $O(N^2)$의 풀이가 있지 않겠냐고 제안했습니다. 결과론적으로 잘못된 판단이었습니다.

 

E(00:17, +0) 무리 없이 구현에 완료하고 1솔브를 챙겼습니다. 기하가 I를 포기하고 L으로 넘어갔습니다. 

 

I/L(00:22) 저는 다시 I로 돌아왔습니다. 기하가 L의 형태를 정리해왔습니다. 증가하는 부분수열의 길이마다 개수가 필요하다고 했습니다. I를 고민하다 말고 L의 dp식을 잠시 고민했습니다. 값이 증가해야한다는 점을 이용해 세그먼트 트리를 $N$개 이용하는 풀이를 가져왔습니다. EDPC같은데서 볼 법한 유형이었고 최근에 비슷한 유형을 접해봐서 쉽게 방향을 잡을 수 있었습니다. 하지만 설명하는게 오래 걸렸습니다. 몇번 같이 연습해보지 않아서 의사소통이 엄청 원활하지는 않았던 것 같습니다. 비슷한 시각 I의 풀이를 시뮬레이션으로 거의 확신했습니다. 모든 값을 어떤 고정된 목표값 $x$가 되도록 만들 수 있는지 묻는 문제는 어렵지 않게 해결할 수 있음을 팀원 모두가 알고 있었습니다. $x$를 가능한 모든 범위에 대해서 돌려 보면 된다는 결론을 내리고 많아야 ```max(A)``` 정도이지 않나 싶어서 구현을 시작했습니다. 동시에 기하가 K를 읽어보기 시작했습니다.

 

K(00:28) 구현이 K를 읽기 시작했습니다. 트리 dfs 왕복 사이클을 돌듯이 순회하면 될 것이라는 직관을 설명했습니다. 비유를 오일러 투어로 들었지만 결과론적으로 잘못 든 비유였던 것 같습니다. 현장에서 만나서 했으면 그림을 그려서 보여줬을 듯 합니다. 

 

I(00:31, -1) I를 틀렸습니다. 대회가 끝나고 나온 얘기 중 하나는 I의 목표값의 최솟값의 상한이 100만정도까지 될 수 있다는 것이었습니다. 이걸 발견하지 못했고, 오랜 시간 물려있었습니다.

 

I(00:43, -2) 결국 못참고 목표값의 상한을 5000으로 수정해서 제출 후 틀렸습니다. 각 목표값마다 $O(N)$의 시간이 걸리는 풀이였기에 이보다 더 클 수 없다는 점을 깨닫고 다른 풀이로 돌아가야한다는 생각을 했습니다.

 

L(00:45) 기하가 maximal한 증가하는 부분수열의 개수가 필요하다고 했습니다. 이 시점에서 I/K/L을 세 명이 세 문제를 동시에 보면서 정신없이 지나갔습니다. 결과적으로는 K는 어려웠고, I는 번아웃이 왔고, L은 식 정리가 침착하게 되지 않았습니다. 마음이 급해 빠르게 풀고 다음 문제를 보려는 조급함이 독이 되지 않았나 싶습니다. 기하가 I의 코드를 동시에 읽으면서 제가 K의 가능한 경우를 그려봄과 동시에 구현이 L의 풀이를 고민하고 있었습니다. 각자 자기가 잡은 문제가 아닌 문제를 동시에 컨트롤하고 싶었던 것 같습니다.

 

L(01:07) 구현이 L의 풀이를 내왔습니다. 제가 구한 증가하는 부분수열의 개수를 믿고 그 다음부터 자연어 풀이를 써왔습니다. 하지만 여전히 maximal에서 이슈가 있습니다. 

 

I(01:14) 기하가 이분 탐색 아이디어를 가져왔습니다. 다만 단조성이 없다는 사실을 금방 깨달았고 이분 탐색 아이디어를 무시했습니다. 결과적으로 옳았습니다.

 

L(01:16) 구현이 본인의 풀이를 손으로 계산해 예제가 옳게 나옴을 확인했습니다. 구현은 일정 상 중도퇴실해야했기에 기하가 구현했습니다. 이 즈음 구현이 퇴실했습니다.

 

I(01:21, +2) 어느 시점이었는지 잘 기억나지 않지만 I의 풀이를 알았습니다. 맨 처음에 생각했던 홀수번째 합과 짝수번째 합의 차가 항상 일정하다는 점을 이용하면 됐습니다. 기하가 $N$이 짝수일 때 목표 값을 무한히 큰 정수 하나만 봐도 된다고 했던 것을 듣고 케이스워크를 나눠서 코드를 짰는데, 홀수일 때 목표치를 잡을 수 있음을 그 이후에 깨달았습니다. 열심히 구현해서 맞았습니다.

 

 

L(01:20, -1) 비슷한 시각 기하가 L을 구현하고 TLE를 받았습니다. 기하는 분명 파이썬이 느려서 시간 내에 돌지 않는 것이라고 판단해 저에게 C++ 번역을 부탁했습니다. 

 

L(01:33) 번역을 완료하고 예제가 나오지 않는 점을 확인했습니다. 펜윅 트리에서 without return 오류가 있었습니다. 사용 중인 TDM 컴파일러는 웬만한 곳에서 그냥 실행시키기 때문에 에러메시지 없이 틀린 값을 받아 문제가 생겼습니다. 런타임 에러의 종류는 채점기가 알려주지 않지만 기하가 디버깅 해서 발견했습니다.

 

L(01:37, -2) 리턴 문구를 삽입 후 제출해 WA를 받았습니다. 

 

K(01:43) 기하가 K를 건드리기 시작했습니다. 이전에 그려둔 그림을 통해 모든 정점의 간선 위치에 따라 최대 5가지 패턴이 나옴을 설명해줬습니다. 

 

L(01:46, +2) 파이썬 bigint를 생각하면 C++에서는 모듈로 연산을 더 자주해줘야 합니다. 예제1이 옳게 나오면 그 문제 뿐이겠거니 싶어 모듈로 연산을 코드 처음부터 끝까지 10억이 넘어갈 수 있는 모든 위치에 해줬고 특히 뺄셈의 경우 더 조심히 보정해 맞았습니다. 스코어보드를 보고 B로 넘어갔는데, 넘어가면서 기하에게 J를 확인해달라고 부탁했습니다. 결과적으로 좋은 판단이었습니다. I에서 멈춰있을 때 뇌를 환기하기 위해 J를 잠시 끄적여놨는데, 구간별로 정렬하고 범위가 겹치는 구간을 잘 비벼넣기정도로 설명해줬는데도 뭔가 하기 시작했습니다.

 

B(02:04) 중요한 관찰을 했습니다. 가능한 제출 시각의 최솟값을 구하라는 것으로 보아 이분 탐색이리라 생각했습니다. 단조성에 대한 증명을 하자마자 문제를 빠르게 환원했습니다. 결국 구간이 있을 수 있는 범위가 주어지면 겹치지 않게 배치할 수 있냐는 문제가 되었습니다.

 

B/J(02:13, 0) 두 문제가 거의 동시에 풀렸습니다. 제가 B, 기하가 J를 잡고 둘다 서로 조용히 구현을 했던 것 같습니다. J는 제가 정확한 작동을 모르고, B는 구간이 있을 수 있는 범위의 상한이 모두 같다는 점을 이용하면 뒤에서부터 그리디하게 채울 수 있음을 알았습니다. 이 시점에서 8솔브를 확인하고 상위 20위 이내에 들어갈 것이라고 거의 확신했습니다. 동시에 여기서 그만 풀어도 되겠다고 얘기했습니다. 하지만 시간이 40분 이상 남았다는 점과 최상위권을 노려보고싶었기 때문에 다른 문제를 풀기로 했습니다. 

고려해볼만한 문제는 G 또는 K였는데, 프리즈 이후였기 때문에 두 문제 중 어느 문제가 많이 맞은 문제인지 알 수 없었습니다. 이전에 계속 봐왔던 K를 보기로 했습니다.

 

K(02:15) 기하가 그래프의 중요한 성질 중 하나인 차수 4인 정점은 3 이상인 정점과 인접할 수 없음을 확인했습니다. 그걸 듣자 마자 차수 3인 정점끼리 인접한다면 어떤 형태로 붙어있어야 한다는 것을 정리하고 가능한 순회 방법을 그렸습니다. 이때 그림을 서로 보여주기 곤란했다는 점이 어려웠습니다.

K(02:19) B/J 솔브 이전에 했던 관찰 중 하나는 트리 간선 별 회로의 진입/진출 위치에 대한 정리였습니다. 이를 토대로 트리 dp를 한다면 가능성 판정 정도는 할 수 있지 않나 얘기했고 기하가 구현을 시작했습니다.

K(02:42) 기하가 구현을 마치고 예제를 요구했습니다. 추가로 문제를 더 풀기 곤란한 시점이라고 생각했어서 더 할 일이 없던 차였기 때문에 예제를 만들려고 시도했습니다. 마침 본문에 있던 그림이 가능한 예제였기 때문에 본문에 있던 예제를 입력 형식에 맞춰 전달했습니다.

K(02:47) 본문에 있던 예제의 실제 해를 손으로 구성해봤습니다. 손으로 구성하며 확인한 점은 임의로 진입/진출을 매핑한다고 해서 그에 맞는 회로가 존재하지 않을 수 있다는 점이었습니다. 이 시점에서 이런 형태로 풀기 위해서는 사용할 수 있는 모든 진입/진출 위치에 대해서 타일을 전부 가지고 있고 각 정점이 어떤 타일의 어떤 방향으로 마무리했을 때를 저장한 뒤 dp 과정에서 이를 모두 계산해줘야 했다는 것을 깨달았습니다. 이 방법으로 해결한 팀이 있다는 것 같았습니다. 차수 3인 정점이 문제였는데, 사용할 수 있는 타일이 10가지 내외였을 것이라고 파악했기 때문에 아주 못풀 방법은 아니었던 것 같습니다마는 남은 시간 내에 해결할 수 없다고 판단하고 여기서 마무리했습니다. 

 

 

최종 스코어 8솔브 22등으로 마무리했습니다. 8솔브 팀의 대부분이 G를 시도하지 않았습니다. 이것이 8솔브와 9솔브를 가르는 분기점이 아니었나 싶습니다. 중간에 잠깐 읽었을 때 확률 얘기가 나와서 귀찮은 계산이 있지 않을까 하고 지레 겁먹고 펴보지 않았는데 생각보다 어렵지 않게 해결가능하다는 것 같았습니다. 본선 전에 업솔빙해볼 법한 문제 같습니다.

A. Frog 1

문제 요약: 다음 칸 또는 그 다음 칸으로 점프할 수 있고, 그때 비용은 높이 차일때 칸 $1$에서 칸 $N$으로 이동하는 최소 비용

풀이:

점프 하나를 간선 하나로 해석하면 dp 점화식 ```dp[i] = min(dp[i-1] + abs(h_{i}-h_{i-1}), dp[i-2] + abs(h_{i}-h_{i-2}))```를 얻을 수 있습니다. top down으로 구현하면 $i-2$가 음수가 될 수 있음에 유의해야 하며 bottom up으로 구현하면 $N$보다 큰 padding을 마련해야 합니다. 

 

B. Frog 2

문제 요약: A번 문제에서 한 번에 점프할 수 있는 거리가 최대 $K$인 문제

풀이:

A와 동일하게 해결하면 됩니다. 업데이트 간선의 개수는 $NK$개입니다.

 

C. Vacation

문제 요약: $i$번째 날에 A,B,C를 하면 얻을 수 있는 행복도는 각각 $a_i, b_i, c_i$이고 이틀 연속으로 같은 행동을 할 수 없을 때 행복도의 최댓값

풀이:

```dp[i][j]```를 $i$번째 날에 $j$번 일을 했을 때의 행복도의 최댓값을 관리하게 하면 ```dp[i]```는 ```dp[i-1]```에만 의존하므로 $i$를 증가시키면서 업데이트하면 됩니다. 업데이트 간선의 개수는 $6(N-1)$개입니다.

슬라이딩 윈도우를 통해 해결할 수도 있습니다.

 

D. Knapsack 1

문제 요약: 비용이 $w$이고 가치가 $v$인 물건을 비용이 $W$ 이하가 되게 고를 때 가치 합의 최대

풀이:

일반적인 0-1 knapsack 문제는 다항 시간 내에 풀 수 없음이 알려져 있습니다. 하지만 $W$의 값은 다항 크기가 아니므로 이를 이용해야 합니다.

```dp[i][j]```를 $1$번 물건부터 $i$번 물건까지 이용해 비용이 $i$인 선택을 할 때 최대 가치라고 하면 비용이 $w$이고 가치가 $v$인 물건을 추가로 선택하면 ```dp[i+1][j+w]```에 ```dp[i][w]+v```인 경우가 추가되는 것과 같습니다. 이를 ```max```로 관리하면 ```dp[N]```에 전체 최적해를 가지게 됩니다. 업데이트 간선의 개수는 최대 $WN$개입니다. 한편 ```dp[i]```는 ```dp[i-1]```에만 의존합니다. 따라서 첫 번째 인덱스를 슬라이딩 윈도우로 관리할 수도 있고, $j$ 인덱스의 업데이트 방향이 증가하는 방향이므로 큰 인덱스부터 관리하면 크기 $W$인 배열 하나만으로 해결할 수 있습니다.

 

E. Knapsack 2

문제 요약: 비용이 $w$이고 가치가 $v$인 물건을 비용이 $W$ 이하가 되게 고를 때 가치 합의 최대

풀이:

D번과 다른 점은 $W$의 상한이 커진 대신 $v$의 하한이 작아졌습니다. 파라메트릭 서치와 같은 테크닉으로 dp 식을 뒤집어 생각하면 D번에서는 어떤 용량을 가지는 가치의 최댓값을 구했다면 여기서는 어떤 가치를 가지는 용량의 최솟값을 관리하면 될 것 같습니다. 

 

같은 방식으로 ```dp[i][j]```를 $i$번 물건까지 사용해 가치가 $j$가 되게 하는 조합의 용량 합 최소값으로 두면 ```dp[i+1][j+v]```에 ```dp[i][j]+w```를 업데이트하는 것과 같고 min 업데이트를 이용해 구할 수 있습니다. ```dp[0][j]```에서 $j$가 0이 아니면 불가능하므로 min의 항등원인 무한대로 초기화해서 구해야 함에 유의해야 합니다. 마찬가지로 업데이트 간선의 개수는 최대 $N\sum v$이고 $i$의 의존성을 이용해 크기 $\sum v$인 배열만으로 해결할 수 있습니다.

 

F. LCS

문제 요약: 두 문자열의 최장 공통부분수열

풀이:

두 문자열의 길이가 각각 $i$,$j$인 접두사의 LCS를 구하는 dp를 구현하면 됩니다. 이는 각각 $i$,$j$번째 문자를 추가하는 경우로, 두 문자가 같으면 ```dp[i][j] = dp[i-1][j-1]+1```, 다르면 ```dp[i][j] = max(dp[i-1][j], dp[i][j-1])```임을 이용하면 격자 모양의 dag를 얻을 수 있습니다. 업데이트 간선의 개수는 최대 $2|s||t|$개 있습니다.

 

G. Longest Path

문제 요약: Unweighted directed acyclic graph에서 가장 긴 경로의 길이

풀이:

dp 식을 바로 써보면 ```dp[v] = max(dp[u]+1: (u,v) \in E)```입니다. 1번 정점에서 출발하는 것이 고정되어 있으므로 $O(M)$에 해결할 수 있습니다. connected component에서 ```E>=V-1```임을 이용하면 $O(N+M)$으로 쓰지 않아도 됨을 알 수 있습니다.

 

H. Grid 1

문제 요약: 장애물이 있는 격자에서 수직인 두 방향만 이용해서 이동할 수 있는 경우의 수

풀이:

이동 가능한 방향으로 간선을 그리면 dag를 쉽게 얻을 수 있습니다. 어떤 칸에 도달하기 위해서 직전에 방문했어야 하는 칸은 많아야 두 개입니다. 직전에 방문했어야 하는 두 칸에 도착하는 경로의 수를 각각 알고 있으면 두 경로 개수의 합이 이 칸에 도착하는 경로의 수입니다. 업데이트 간선의 개수는 최대 $2HW$입니다.

 

I. Coins

문제 요약: 1이 나올 확률이 각각 $p$인 독립시행 결과 1이 나온 횟수마다의 확률

풀이:

확률론적으로 접근하면 확률이 각각 독립이므로 시행을 한 번 더 하는 경우를 각각 곱의 법칙으로 구할 수 있습니다. ```dp[i][j]```를 $i$번 시행까지 마쳤을 때 $j$번의 1이 나올 확률로 두면 확률 $p$인 시행을 추가하는 경우는 ```dp[i+1][j] = dp[i][j-1]*p + dp[i][j]*(1-p)```임을 확률론적으로 얻을 수 있습니다. dp 상태는 ```i>=j```인 경우 뿐이므로 업데이트 간선의 개수는 최대 ${N^{2}}$개입니다.

 

J. Sushi

문제 요약: $N$개의 접시 위에 초밥이 각각 최대 3개 올려져 있고 접시를 균등하게 뽑아 그 위에 초밥을 먹을 때 모두 먹기까지 시도 횟수의 기댓값

풀이:

모든 접시는 동등하므로 $0$,$1$,$2$,$3$개의 초밥이 올려진 접시의 개수를 각각 $a$,$b$,$c$,$d$라고 뭉뚱그려도 됩니다. 이때 $a+b+c+d$가 항상 $N$이므로 이중 세 개의 값만 가지고 현재 초밥의 개수를 명확하게 구현할 수 있습니다. 이제 ```dp[b][c][d]```를 이 상태에서 초밥을 모두 먹기까지 시도 횟수의 기댓값으로 두면 ```dp[b][c][d] = 1 + dp[b][c][d] * a/N + dp[b-1][c][d] * b/N + dp[b+1][c-1][d] * c/N + dp[b][c+1][d-1] * d/N```가 성립해야 한다는 것을 알 수 있습니다. 우변의 ```dp[b][c][d]```를 넘겨 정리하면 ```dp[b][c][d] = (1 + dp[b-1][c][d] * b/N + dp[b+1][c-1][d] * c/N + dp[b][c+1][d-1] * d/N) * N/a```가 되어 dp식을 얻은 것을 알 수 있습니다. acyclic인 것은 ```b+c+d```의 값이 작은 상태, ```b+c+d``` 값이 같고 ```d```값이 작은 상태, ```b+c+d```와 ```d``` 값이 같고 ```c```값이 작은 상태로 부터만 오기 때문에 세 값을 축으로 격자를 그려보면 알 수 있습니다.

업데이트 간선의 개수는 최대 $3(b+c+d)(c+d)d$입니다.

 

K. Stones

문제 요약: $K$개의 돌에서 $a$개의 돌을 지울 수 있을 때 승리하는 플레이어

풀이:

$a$가 양쪽 모두에게 동등하므로 내가 패배하는 상태를 상대에게 주는 것이 내가 승리하는 것과 동치입니다. ```dp[i]```를 남은 돌의 개수가 $i$일 때 승리할 수 있는지 여부를 담은 부울린 dp로 잡으면 ```dp[i] = not and(dp[i-a])```입니다. 업데이트 간선의 개수는 최대 $NK$개입니다.

 

L. Deque

문제 요약: 덱의 앞 또는 뒤에서 제거해 제거한 수 만큼 점수를 얻어 점수 차를 최대로 하는 게임을 할 때 최대 점수차

풀이:

$X-Y$를 최소화 하는 것과 $Y-X$를 최대화 하는 것이 완전히 동일합니다. 또한 $X+Y$가 고정되어 있으므로 $X$를 알면 $Y$를 알 수 있기 때문에 각자 자신의 점수를 최대화 하는 것과 동치임을 알 수 있습니다.

```dp[l][r]```을 $l$번째 원소부터 $r$번째 원소로 게임할 때 얻을 수 있는 $X-Y$의 최댓값으로 두면 ```dp[l][r] = max(a_l - dp[l+1][r], a_r - dp[l][r-1])```임을 확인할 수 있습니다. 하나를 제거한 상태가 되면 더 작은 게임을 선후공이 바뀐 채로 게임하는 것과 같기 때문에 상대가 최대화한 값의 부호를 뒤집어 내가 최대화한 값을 얻을 수 있습니다. 업데이트 간선 개수는 $O(N^2)$개입니다.

 

M. Candies

문제 요약: $N$명의 어린이에게 $K$개의 사탕을 나누어 줄 때 $a$ 이하로 나누어주는 경우의 수

풀이:

$K$의 값이 크지 않기 때문에 $K$를 인덱스로 잡아 dp하려는 생각을 할 수 있습니다. ```dp[i][j]```를 $i$번째 어린이까지 사탕을 나누어 주고 $j$개가 남는 경우의 수라고 하면 ```dp[i][j] = sum(dp[i-1][j+k]: j+k<=K)```가 됩니다. $dp[i]$가 $dp[i-1]$에만 의존하므로 누적 합을 이용한 정적 구간 합을 통해 $O(NK)$에 dp 테이블을 전부 채울 수 있습니다. dp 배열을 재배열하는 경우 점 업데이트 구간 쿼리를 쓰게 되므로 세그먼트 트리를 이용할 수도 있고, 이 경우 $O(NKlgK)$의 시간과 $O(K)$의 공간으로 해결할 수 있습니다.

 

N. Slimes

문제 요약: 이웃한 두 슬라임을 합칠 때 합친 크기 만큼 비용이 들 때 모든 슬라임을 합치는 데 드는 최소 비용

풀이:

이웃한 슬라임만 합칠 수 있으므로 구간을 합치는 것으로 이해해도 됩니다. ```dp[l][r]```을 $l$번째 슬라임부터 $r$번째 슬라임까지 합치는 최소 비용으로 두면 ```dp[l][r]```은 마지막 합치는 시행 직전 상태는 ```l<=i<r```인 $i$를 기준으로 두 구간이 나뉘어 있었어야 합니다. 따라서 ```dp[l][r] = min(dp[l][i] + dp[i+1][r] + sum(l:r): l<=i<r)```가 성립하고, 구간의 길이가 짧은 구간에서 긴 구간 방향으로 업데이트가 일어나므로 dag가 됨을 알 수 있습니다.

 

이때 업데이트 간선의 개수가 $O(N^3)$개이므로 조금 더 최적화가 필요합니다. 구간을 합치는 데 드는 비용이 구간합이기 때문에 ```sum(a:d)>=sum(b:c)```와 ```sum(a:d)+sum(b:c)>=sum(a:c)+sum(b:d)```가 성립하므로 Knuth optimization 또는 Knuth-Yao speedup이라는 테크닉을 이용할 수 있습니다. dp 식의 min 부분은 주어진 값 가운데 하나를 선택하는 함수인데, 구간 마다 선택한 인덱스를 ```opt[l][r]```이라 한다면 ```opt[l][r-1] <= opt[l][r] <= opt[l+1][r]```이 성립하고 dp값과 동시에 구해주면 같은 길이의 dp를 모두 구하는 데 드는 min 탐색 비용 합이 $O(N)$이므로 전체 $O(N^2)$에 해결할 수 있습니다. ```opt``` 값에 관한 부등식의 증명은 어렵기 때문에 생략합니다.

 

edit: $O(N^3)$으로도 해결할 수 있다고 합니다.

 

O. Matching

문제 요약: 남자 또는 여자로 이루어진 이분 그래프에서 완전 매칭의 개수

풀이:

완전 매칭의 개수를 세야 하므로 1번 남자는 어떤 여자와 매칭되어야 합니다. 1번 남자를 어떤 여자와 매칭시키고 나면 2번 남자 또한 다른 어떤 여자와 매칭되어야 합니다. 같은 방식으로 번호가 작은 남자부터 순서대로 여자를 매칭하는 경우의 수를 세줄 수 있습니다. ```dp[i][j]```를 $i$번 남자까지 매칭한 결과 매칭된 여자의 비트마스크 집합의 결과가 $j$인 경우의 수로 두면 $i$의 모든 간선에 대해서 업데이트해줄 수 있습니다. 이때 ```popcount(j) = i```가 성립하므로 $i$ 인덱스는 필요하지 않습니다. popcount가 작은 인덱스부터 큰 인덱스 순서대로 업데이트해주면 popcount가 가장 큰 인덱스에서 완전 매칭의 개수를 얻을 수 있습니다. 업데이트 간선의 개수는 최대 $O(N 2^N)$개입니다.

 

P. Independent Set

문제 요약: 트리에서 독립 집합의 개수

풀이:

임의의 루트를 잡으면 rooted tree를 얻을 수 있습니다. rooted tree에서 독립 집합은 루트를 포함하는 경우와 포함하지 않는 경우로 나눌 수 있습니다. 루트를 포함하는 경우 maximal subtree의 루트는 포함할 수 없음을 이용하면 루트를 포함하는 경우와 포함하지 않는 경우의 독립 집합의 개수를 따로 세 줘야 함을 알 수 있습니다.

```dp[i][0]```을 $i$를 루트로 하는 서브트리에서 루트를 포함하지 않는 독립 집합의 개수, ```dp[i][1]```를 루트를 포함하는 독립 집합의 개수로 두면 ```dp[i][0] = \prod (dp[j][1]+dp[j][0]: (i,j) \in E)```, ```dp[i][1] = \prod (dp[j][0]: (i,j) \in E)```임을 알 수 있습니다. 각 간선마다 dp 업데이트가 두 번씩 일어나므로 업데이트 간선의 개수는 $2N-2$개입니다.

 

Q. Flowers

문제 요약: $(h,a)$ 꼴의 순서쌍의 수열에서 $h$가 단조 증가하는 부분 수열의 $a$ 값의 최댓값

풀이:

$i$번째로 끝나는 부분 수열의 최댓값은 $i$ 이전에 끝나는 부분 수열의 최댓값 뒤에 $i$번째 $a$를 더한 값입니다. 이를 ```dp[i]```라고 두면 ```dp[i] = max(dp[j]: j<i, h[j]<h[i])+a[i]```가 됩니다. 이를 $h$가 작은 $i$부터 순서대로 업데이트해주면 두 번째 조건을 자동으로 만족하게 됩니다. $i$보다 작은 구간의 최댓값을 구하는 것은 세그먼트 트리를 이용해 $O(lgN)$에 구할 수 있기 때문에 총 $O(NlgN)$에 모든 dp 값을 구할 수 있습니다. $h$가 가장 작은 인덱스의 경우 0번째에 $h$와 $a$가 모두 0인 꽃을 먼저 선택했다고 봐도 무방하기 때문에 예외 처리 없이 해결할 수 있습니다.

 

R. Walk

문제 요약: Directed graph에서 길이가 $K$인 서로 다른 walk의 개수

풀이:

길이가 $a+b$인 walk는 길이가 $a$인 walk와 $b$인 walk로 분리할 수 있고 그 방법이 유일합니다. 반대로 한 시작점과 반대쪽의 종점이 같은 두 walk를 합쳐서 긴 walk를 만들 수 있고 이 방법도 유일합니다. 따라서 y에서 시작해 길이가 $a$인 walk의 집합 $A$, y에서 출발해 길이가 $b$인 walk의 집합 $B$, y를 포함하는 길이가 $a+b$인 walk의 집합 $C$에 대해 $A\times B \cong C$가 성립합니다. $A$의 출발점과 $B$의 도착점 또한 명시해 주면 adjacent matrix의 행렬 곱과 같음을 알 수 있습니다. adjacent matrix의 $K$제곱을 binary lifting으로 구한 뒤 모든 항의 합을 구하면 $O(N^3 lgK)$ 시간에 답을 얻을 수 있습니다.

 

S. Digit Sum

문제 요약: $K$보다 작은 양의 정수 중 자릿수의 합이 $D$의 배수인 수의 개수

풀이:

$K$가 크기 때문에 산술적으로 접근하기 곤란합니다. leading zero를 허용하면 $K$와 같은 자릿수의 정수를 많이 관찰해야 한다는 생각을 할 수 있습니다. 이때 $K$와 leading digit이 같은 수는 계산하기 힘들지만 적어도 하나가 다르면 그 아랫 자리는 자유롭게 선택할 수 있음을 확인할 수 있습니다. ```cnt[i]```를 $K$와 $i$ 길이의 prefix가 같은 정수를 $D$로 나눈 나머지가 0인 정수의 갯수로 두면 ```cnt[i]```는 $i+1$번째 자리부터 자릿수 합이 ```-sum[K[0:i]]```인 원소의 개수와 같습니다. $i+1$번째 자릿수는 $K$보다 작은 경우만 계산하면 됩니다. $K$와 같은 경우는 ```cnt[i+1]```에서 계산할 것이기 때문에 중복 계산을 피하기 위해 $i+1$번째 자릿수가 $K[i+1]$보다 작은 경우만 생각합니다. 그러면 ```cnt[i]```를 ```cnt[i][j]```꼴로 나눠서 $K$와 길이 $i$의 prefix가 같은 정수 중에 $i+1$번째 자릿수가 $j$인 정수 중 $D$로 나눈 나머지가 0인 개수로 두면 ```cnt[i][j]```는 $i+2$번째 자리부터 자릿수 합이 ```-sum[K[0:i]]-j```인 원소의 갯수와 같습니다. 여기서는 모든 자리의 자릿값을 0부터 9까지 완전히 자유롭게 선택할 수 있습니다. leading zero를 포함하여 $x$자리인 정수 중에서 $D$로 나눈 나머지가 $y$인 정수의 개수를 ```dp[x][y]```로 두면 dp값은 쉽게 구할 수 있습니다. 이 dp의 업데이트 간선의 개수는 대략 $10lgK$개입니다. 이제 모든 ```cnt[i][j]```의 값을 구하면 총 $O(DlgK)$개의 값을 각각 상수시간에 구할 수 있습니다.

 

T. Permutation

문제 요약: 주어진 부등식을 만족하는 서로 다른 순열의 갯수

풀이:

부등식을 만족하면 실제 수의 배열은 어떻게 주어지더라도 무관함을 이용할 수 있습니다. 앞에서부터 $i$개의 수를 채운 결과 $i$번째 값 보다 작은 원소의 개수가 $j$개가 되는 순열의 개수를 ```dp[i][j]```라고 둡니다. 그리고 ```s[i]```에 따라 두 가지 경우의 수로 나뉩니다.

 

```s[i]```가 <인 경우라면 이전까지 구한 순열의 마지막 원소보다 큰 원소를 취해야 합니다. ```dp[i][j]```에서 마지막 원소보다 큰 원소는 ```i-dp[i][j]-1```개 있습니다. 이중 하나를 고른 뒤 이보다 크거나 같은 이전에 등장한 모든 원소에 1을 더해주는 방법으로 $i+1$번째 원소를 특정할 수 있습니다. ```dp[i+1][k] += dp[i][j]: k>j```와 같은 구간 업데이트를 진행할 수 있습니다.

반대로 ```s[i]```가 >인 경우라면 1부터 $j$까지 고를 수 있으므로 ```dp[i+1][k] += dp[i][j]: k<=j```와 같은 구간 업데이트를 진행할 수 있습니다. ```dp[i]```가 ```dp[i-1]```에만 의존하므로 $i$를 고정해 두고 구간 업데이트 쿼리를 이용할 수 있고, imos 등의 방법으로 $i$마다 $O(N)$에 해결할 수 있습니다. 반대로 ```dp[i][k] = \sum (dp[i-1][k])``` 꼴로 수정해 구간 합 쿼리를 이용할 수도 있습니다. 세그먼트 트리를 이용할 수도 있습니다.

 

U. Grouping

문제 요약: $N$개의 원소를 파티션 지어 같은 부분에 들어간 쌍마다 점수를 얻을 때 점수의 최댓값

풀이:

모든 원소를 분리할 수 있으므로 답은 0 이상입니다. ```dp[i]```를 비트마스크가 i인 부분집합을 파티션 지을 때 얻을 수 있는 점수의 최댓값으로 우선 정의하고 싶어집니다. top down이나 bottom up이나 비트를 뒤집으면 같은 모양이기 때문에 업데이트 간선의 개수는 같습니다. bottom up 관점에서 볼 때 ```dp[i] = max(dp[i-j] + cost(j): j \in i)```임을 확인할 수 있습니다. ```cost(j)```는 비트마스크가 $j$인 부분집합의 점수입니다. 이를 나이브로 구현하면 맞을 수 있습니다.

업데이트 간선의 개수는 모든 부분집합의 모든 부분집합의 원소 개수 합인데, 이항정리를 이용해서 업데이트 간선의 개수를 구할 수 있습니다. 비트마스크 $i$의 부분집합의 개수는 $2^{popcount(i)}$입니다. popcount가 같은 $i$끼리 모으면 총 업데이트 간선의 개수는 $\sum _ {k=0} ^{k=N} 2^{N} nCr(N,k)$인데 이항정리에 의해서 $(2+1)^N$과 같으므로 총 $3^N$개의 업데이트 간선이 있습니다.

cost를 나이브로 구하면 매 업데이트마다 최대 $N^2$번 더 연산하게 되므로 cost를 전처리해야할 수 있습니다.

 

V. Subtree

문제 요약: Unrooted tree에서 특정 정점을 포함한 connected subgraph의 개수

풀이:

rooted tree에서 subtree의 개수를 세는 것은 ```dp[v] = \prod (dp[u]: (u,v) \in E) + 1```으로 상대적으로 쉽습니다. 만약 dp가 체의 원소라면 간선을 쉽게 끊을 수 있습니다. root 정점 r, r의 자식 v에 대해 ```dp[r] = (dp[r]-1)/(dp[v]) + 1```, ```dp[v] = (dp[v]-1)*dp[r] +1```을 이용하면 루트를 r에서 인접한 v 정점으로 바꾼 경우의 dp 배열을 $O(1)$에 얻을 수 있습니다. 이 과정을 통해 전체 트리를 dfs하면 각 정점이 루트일 때 루트의 dp 값을 $O(N)$에 구할 수 있습니다.

체의 원소가 아니기 때문에 나누기 연산을 사용할 수는 없지만 나누는 행위가 r의 모든 자식 정점 중 v를 제외한 모든 정점을 합치는 것과 같음을 이용할 수 있습니다. 모든 자식 정점 v마다 v가 아닌 정점의 dp 값을 모으는 연산을 하게 되면 $\sum deg(v)^2$만큼 연산이 필요해 비용이 가장 큰 정점에서 $O(N^2)$보다 작을 수 없습니다. 대신 v의 접두/접미 누적합을 이용하면 $O(deg(r))$의 전처리를 통해 각 v마다 v를 제외한 dp값을 $O(1)$에 얻을 수 있습니다. 각 정점이 루트가 될 때마다 $O(deg(r))$의 전처리가 필요하므로 총 전처리 비용은 $O(\sum deg(r)) = O(N)$이 됩니다.

 

W. Intervals

문제 요약: 몇 개의 정수를 선택해 주어진 구간이 선택한 정수를 포함하는 경우 점수를 획득할 때 점수의 최댓값

풀이:

```dp[i]```를 선택한 정수 중 최댓값이 $i$일 때 점수 최댓값으로 두고 작은 수부터 순서대로 선택하고 싶어집니다. $i$를 선택하기 직전에 선택한 가장 큰 정수가 $j$라면 ```dp[i] - dp[j]``` 값은 $i$를 포함하면서 $j$를 포함하지 않는 구간의 가중치 합이 됩니다. 이를 나이브로 구하면 $O(M)$의 비용이 들고 각 $j$마다 구하면 총 $O(N^2M)$만에 답을 얻을 수 있습니다. $i$보다 작은 범위와 겹치는 구간의 가중치 합 등을 누적합으로 하는 차분 배열은 올바른 dp값의 차를 구할 수 없습니다. 

 

dp 식을 써보면 ```dp[i] = max(dp[j] - cost(i,j): j<i) + sum(i)```로 정리할 수 있습니다. 이때 ```cost(i,j)```는 $i$와 $j$를 동시에 포함하는 구간의 가중치 합, ```sum(i)```는 $i$를 포함하는 구간의 가중치 합입니다. 가중치가 $A$인 ```cost(i,j)```에 포함되는 구간 ```[L:R]```은 ```cost(i,L:R)```에 $-A$만큼 영향을 줍니다. dp값을 세그먼트 트리로 관리하면 해당 구간이 $i$를 포함하는 동안 $[L:R]$에 $-A$만큼 기여합니다. 이와 독립적으로 ```sum(i)```에 포함되는 구간은 $j$에 관계없이 영향을 줍니다. 따라서 $j$를 전체 범위로 확장해 보면 ```sum(i)```에 포함되는 모든 구간 $[L:R]$은 $[L:R]$이 아닌 범위에서만 $A$만큼 영향을 주는 것으로 볼 수 있습니다. 

 

실제로 구현을 구체화해 보면 $i$를 작은 것부터 순회하면서 $i$를 포함하는 모든 구간만을 동시에 관리합니다. 이때 세그먼트 트리를 이용해 해당 구간이 아닌 범위의 값을 구간의 가중치 만큼 증가시킵니다. 이때 $i$보다 작은 인덱스에서 ```dp[j] - segtree[j]```값의 최댓값이 ```dp[i]```값이 됩니다. 세그먼트 트리의 각 인덱스마다 ```dp[i]```값을 증가시켜놓으면 한 번의 세그먼트 트리 쿼리만으로 dp값을 구할 수 있습니다. 각 구간이 세그먼트 트리에 한 번 들어갔다 나오고 각 인덱스마다 세그먼트 트리의 구간 쿼리를 한 번 수행하므로 총 $O((N+M)lgN)$에 답을 구할 수 있습니다. 일본에서 starry sky tree로 알려진 유사 세그먼트 트리로 해결할 수도 있습니다.

 

X. Tower

문제 요약: 무게 $w$인 블럭 위에 무게 합이 최대 $s$인 블럭까지 쌓을 수 있을 때 쌓인 블럭의 가중치 합 최대

풀이:

블럭을 쌓는 순서가 중요하므로 블럭을 쌓는 순서를 정하는 것이 중요합니다. 각 블럭의 무게를 $W[i]$, 쌓을 수 있는 한계를 $S[i]$, 가중치를 $V[i]$라고 하고 쌓을 수 있는 한계를 용량이라고 부르면 좋아 보입니다. 용량 $s$ 위에 블럭 $i$, $j$가 아래에서부터 순서대로 쌓여있을 때 가장 꼭대기에 추가로 쌓을 수 있는 용량의 크기는 ```min(s-W[i]-W[j],S[i]-W[j], S[j])```입니다. 반대로 블럭 $j$, $i$가 순서대로 쌓여있다면 ```min(s-W[i]-W[j],S[j]-W[i], S[i])```입니다. 이때 $i$를 위에 쌓는 것이 더 이득이려면 ```min(s-W[i]-W[j],S[i]-W[j], S[j]) <= min(s-W[i]-W[j],S[j]-W[i], S[i])```를 만족해야 합니다. 가장 첫 항은 항상 같기 때문에 우변의 최솟값이 ```s-W[i]-W[j]```인 경우는 고려하지 않아도 됩니다. $i$와 $j$가 대칭식이기 때문에 좌변의 최솟값인 경우도 동일합니다. 따라서 ```min(S[i]-W[j], S[j]) <= min(S[j]-W[i], S[i])```가 성립하면 $i$를 위에 쌓는 것이 항상 유리합니다. 증명 없이 이 식을 기준으로 블럭을 정렬해 dp식을 세우면 맞을 수 있습니다.

 

식을 약간 변형하면 ```min(S[i]+W[i], S[j]+W[j]+W[i]) <=  min(S[j]+W[j], S[i]+W[j]+W[i])```처럼 쓸 수 있습니다. 우변의 최솟값이 ```S[i]+W[j]+W[i]```라면 우변은 ```S[i]+W[i]```보다 클 수 없기 때문에 항상 부등식이 성립합니다. 따라서 이 경우도 제외할 수 있습니다. 따라서 ```S[i]+W[i]<=S[j]+W[j]```인 경우에 $i$를 위에 쌓는 것이 유리하므로 $S+W$를 기준으로 큰 블럭부터 쌓는 것이 유리합니다.

 

```S[i]+W[i]<=S[j]+W[j]```이고 $i$ 위에 $j$를 쌓을 수 있다면 ```min(s-W[i],S[i])<=W[j]```를 만족합니다. 식을 변형해서 ```min(s-W[j],S[i]+W[i]-W[j])<=W[i]```를 얻습니다. 만약 둘 중 더 작은 값이 $s-W[j]$라면 문제 없이 $j$ 위에 $i$를 쌓을 수 있습니다. 아니라면 ```S[i]+W[i]-W[j] <= s-W[j] <= W[i]```를 얻어 ```S[i]<=W[j]```임을 알 수 있습니다. ```min(s-W[j],S[j]) <= min(W[i],S[j]) <= W[i]```이므로 이 경우도 $j$ 위에 $i$를 쌓을 수 있습니다. 따라서 $S+W$가 큰 블럭부터 순서대로 쌓는 dp를 구성하면 해결할 수 있습니다.

 

이제 마지막으로 ```dp[i][j]```를 $i$번째로 $S+W$가 작은 블럭까지 쌓았을 때 여유 용량이 $j$일 때 가중치 합 최대로 두면 0-1 배낭 문제로 해결할 수 있습니다. 정렬에 $O(NlgN)$의 시간이 필요하고 업데이트 간선의 개수는 최대 $O(N \sum s)$개입니다.

 

Y. Grid 2

문제 요약: 장애물이 있는 격자에서 수직인 두 방향만 이용해서 이동할 수 있는 경우의 수

풀이:

문제 제한이 크므로 모든 경우의 수를 다 구할 수 없습니다. $N$개의 장애물을 장애물이 아닌 도착점으로 생각합니다. ```dp[i]```를 $i$번째 장애물에 다른 장애물을 거치지 않고 도달할 수 있는 경로의 수로 둡니다. ```dp[i]```는 다른 장애물에 상관 없이 $i$번째 장애물에 도달하는 경우의 수에서 다른 장애물을 거쳐 도착하는 경우의 수를 뺀 값입니다. 또한 ```dp[i]```는 $i$가 처음 만난 장애물이고 그 자리에서 멈춘 경우의 수로 이해할 수도 있습니다. 따라서 ```dp[i] = nCr(r[i]+c[i]-2,r[i]-1) - \sum (dp[j] * nCr(r[i]+c[i]-r[j]-c[j],r[i]-r[j])```가 성립합니다. $j$의 범위에 따라 이항계수를 구할 때 문제가 생길 수 있음에 주의해야합니다.

$(H,W)$에 도달하는 경우의 수는 $(H,W)$에 장애물을 하나 더 추가로 놓고 이 장애물에 처음으로 도달하는 경우의 수를 세는 것과 같습니다. 업데이트 간선의 개수는 최대 $O(N^2)$개이고 이항계수를 상수시간에 구할 수 있도록 $O(H+W)$에 전처리해둘 수 있습니다.

 

Z. Frog 3

문제 요약: 위치가 증가하는 방향으로 점프하는 비용이 높이 차이의 제곱일 때 $1$번 칸에서 $N$번 칸으로 이동하는 최소 비용

풀이:

```dp[i]```를 $i$번 칸으로 이동하는 데 드는 최소 비용이라고 두면 ```dp[i] = min(dp[j] + (h_i-h_j)^2 + C: j<i)```입니다. 식을 변형하면 ```dp[i] = min(-2h_jh_i + dp[j] + h_j^2) + C+h_i^2```이 됩니다. 이는 일차함수의 모임에 대입한 값의 최솟값을 구하는 쿼리로 해결할 수 있습니다. convex hull trick 또는 Li-Chao tree를 통해 ```dp[i]```값을 구한 뒤 직선 ```-2h_i x + dp[i] + h_i^2```을 추가하는 것으로 해결할 수 있습니다. $h_i$가 증가하므로 선형 CHT를 수행할 수도 있고, Li-Chao tree를 통해 $O(Nlgh_N)$에 해결할 수도 있습니다.

'Problem solving' 카테고리의 다른 글

2026 UCPC 후기  (0) 2026.07.17
UCPC 2026 예선 후기  (0) 2026.07.02
Good Bye, BOJ 2025! 후기  (0) 2026.02.23
ICPC 2025 Seoul Regional Competition 후기  (1) 2026.01.08
ICPC 2025 Seoul Regional Nationwide Copetition 후기  (0) 2025.12.30

Good Bye, BOJ 2025!의 온사이트가 공지되었습니다. 선정 기준이 공기되면서 당연히 많은 관심이 기준에 쏠리게 되었습니다.

물론 저는 장소가 더 중요했습니다. 공지된 장소는 서울 강서였고, 신청해서 되면 가고 아니면 집에서 적당히 비비다 말자는 생각이었습니다. 아무래도 1단계 조건이 되긴 하지만 보통 저는 운이 좋지 않은 편이었기 때문에 크게 문제없으리라 생각했습니다. 다이아 난이도 문제는 아직 100문제도 제대로 풀지 못했거니와 플래티넘 문제도 열심히 푼 기억도 없었기 때문에 아무래도 가게 된다면 1단계일 것이고 그렇지 않으면 못가리라 생각했습니다.

그런데 예상치 못하게 4단계에서 선정되었습니다. 아무래도 1,2,3단계 선정된 분들또한 골드를 많이 풀었기 때문에 컷이 내려온게 아닌가 싶습니다. 골드 1000문제 풀기 챌린지를 진행하는 중이기도 했고 특히 저 즈음해서 문제수가 많이 올라왔기 때문이지 않나 싶습니다. 

 

뭐 어떻게 잘 도착했습니다. 사실 저 사진찍은 시점에서 조금 더 헤메긴 했는데 아무 건물이나 들어가서 아무나 붙잡고 건물 위치를 물어보니 친절하게 답해주셔서 쉽게 찾아갈 수 있었습니다. 아무래도 LG 직원분처럼 보였습니다. 진한 서울 말씨에서 서울에 왔다는 체감이 됐습니다.

 

로비에 도착해서부터는 사진이 없습니다. 아무래도 엄청 많은 고수의 분위기에 압도돼서 사진을 찍어야 한다는 생각을 못했던 것 같습니다. 로비에는 @man_of_learning님와 @stonejjun03님이 안내를 봐주셨습니다. @stonejjun03님은 제 이름을 보시고 바로 알아차리신 눈치였지만 @man_of_learning님은 그렇지 못했던 것 같습니다. 심지어 @jhnah917이라고 써있는 명찰을 메고 계셔서 저도 못 알아봤습니다.

 

저는 ICPC 팀노트를 그대로 챙겨갔는데, 핸들이 인쇄되어있어야 한다는 조건을 보지 못했습니다.

사실 이런 깃허브 페이지가 있다는 것도 지금 확인했습니다.

다행히 운영진측의 배려로 현장에서 수기로 작성하는 것을 허용해주셨고, 뒤에 줄서계시던 @nflight11님의 펜을 빌려 핸들을 기입하고 접수를 오랫동안 하고 대회장으로 올라갔습니다.

 

대회가 시작되기 전에는 서로 대화하는 가벼운 시간이 있었습니다. 주최측에서 준비해주신 시간은 아니고 여기 추첨될 만큼 문제를 푼 사람들이면 어느정도 서로 친분이 있는 경우가 종종 있어서 자연스럽게 분위기가 생긴 듯합니다. @nflight11님께 펜을 돌려드리고 여러 사람들에게 아는 척을 했던 것 같습니다. 얘기나눈 분들을 다 하나씩 얘기하고 싶지만 다 기억나지 않는 관계로 공평하게 모두 얘기하지 않겠습니다. 

 

아마 @ryute님이었던 것으로 기억합니다. 대회 시작 직전 앞에서 통제해 주셔서 대회를 시작하게 되었습니다.

결과가 썩 좋지 않습니다. 참가자 평균 실력이 높다 보니 하위권에 머물렀습니다. 

A (00:16): 간단하게 10의 거듭제곱으로 나눈 몫과 나머지의 곱을 구하는 구현이 제일 어려웠습니다. 아마 파이썬을 썼으면 금방 구현할 수 있지 않았나 싶습니다. 아무래도 이걸 빨리 짰으면 50등으로 올라갔을 지 몰랐을 것 같습니다. N이 충분히 작기 때문에 T+N의 구현을 하는 것이 맹점인 문제였습니다.

 

B (-4): 딱 보자마자 harmonic series가 생각났습니다. 그래서 바로 구현에 들어갔습니다. 제곱처럼 짜면 로그로 떨어지고 LlgN에 해결된다는 생각으로 단순 구현을 했는데 쉽지 않았습니다. 요지는 장면을 직접 세면 안되고 프레임에 장면이 몇 개 들어가는지를 빠르게 알아 프레임의 개수를 트래킹하는 것이었습니다. 바로 구현이 안되겠다 싶어 프레임 수를 기준으로 장면 개수를 트래킹하는 파라메트릭 서치로 방향을 틀었는데, 이것이 패착이 된 것 같습니다. 물론 답의 범위가 3천만 미만임을 확인했지만 거기서 마무리했습니다.

 

C: (02:20): 오래 고민을 했습니다. 결국 PBA를 했는데 왠지 optimal은 아니지만 충분히 클 것이라고 판단해 구현했습니다. 끝나고 @kwoncycle님에게 해설을 들었는데 명쾌한 증명이 있었습니다. 

 

D: (01:36, +3): 보자마자 풀이가 보였습니다. 결과적으로 반쪽짜리 풀이였지만 풀이의 핵심 부분이긴 했습니다. dfs 순서대로 제거하면 된다고 생각했지만 WA를 받았습니다. 제 기억으로는 3개의 패널티가 모두 같은 코드였습니다. 1솔브 시점이었기 때문에 조급한 나머지 패널티 신경쓰지 않고 무작정 제출했던 것 같습니다. 아무 생각 없이 정렬해볼까 생각한 순간 풀이가 짜맞춰졌습니다. 20이 맥거핀이라고 생각했지만 아니었다는 것을 깨닫고 바로 AC를 받았습니다.

 

좀 아쉬운 결과를 받았습니다. B를 업솔빙하겠다고 생각했지만 거의 두달동안 손도 안대봤습니다. 아무래도 반성해야 할듯 합니다. 

 

스코어보드 공개는 @jhnah917님이 해주셨습니다. 제 핸들을 보고 어떻게 읽는지 물어보셨던 것 같은데 제가 딴짓하느라 못들어서 대답을 못해드렸습니다. 그래서 제 핸들은 [큐어쩌고]라고 읽는게 되어버렸습니다. 제가 어디 앉아있는지는 어떻게 아셨을까요.

 

스코어보드 공개가 끝나고 @nflight11님과 @hibye1217님이 저녁 파티를 모았습니다. 당초 공지되었던 19:00보다 한 시간 이상 일찍 마무리되어 저녁 파티에 합류하게 되었습니다. 총 9명이 이동했던 것 같습니다. @queued_q님이 가져오신 퍼즐을 구경하면서 식사를 기다렸습니다. 

 

식사를 마치고 다들 버스타고 돌아간다, 지하철타고 돌아간다 등 얘기를 들으니 참 마음이 착잡해졌습니다. 아무래도 서울로 이사가야할 것 같습니다.

https://blueqv.tistory.com/22

 

ICPC 2025 Seoul Regional Nationwide Copetition 후기

ICPC 2025 서울 리저널 인터넷 예선이 끝났습니다. 끝난지는 한참 됐는데 그래도 해 바뀌기 전에 후기는 써야할 것 같아 급히 작성합니다. Just Reboot JungSangHwa라는 팀명으로 출전했습니다. 이상한 뜻

blueqv.tistory.com

 

 

경희대학교 Memoria가 목요일에 부산에 일찍 도착했습니다. Memoria의 987, jwpassion1과 kolorvxl과 저녁을 먹었습니다. 조금 늦은 시간이었지만 잘 먹고 잘 돌아갔습니다.

문제가 여기서 발생했습니다. 구글 맵스가 이미 없어진 버스 노선을 가르쳐 줘서 자정이 넘은 시간에 30분동안 아무 것도 없는 버스 정류장에서 기다리다가 이상함을 눈치채고 다른 이동수단을 찾기 시작했습니다. 마침 휴대폰 배터리가 다 돼 다른 뾰족한 수가 없었습니다. 결국 20여km를 걸어가기로 단행하고 새벽 3시가 되어서야 학교 인근에 도착할 수 있었습니다. 다음날 예비소집에 늦지 않기 위해 별 말 할 새 없이 바로 취침해야 했습니다.

 

예비소집때는 별 문제 없이 잘 도착했습니다. 가장 먼저 에스컬레이터 앞에서 안내중인 PULSE 졸업생 선배(선배는아니고) M00n과 인사를 하고 대회장 앞에서 노숙하고 있는 팀원과 만나 등록해 들어갔습니다. 

연습 세션에는 큰 이슈는 없었습니다. 연습 세션에는 24B가 연습 문제로 나왔는데, kolorvxl이 연습삼아 풀었습니다. 작년 대회때 인상깊게 푼 문제였기 때문에 기억하고있습니다.

 

예비소집이 끝나고 서울대학교 TempleRun팀, DidYouCheckEERTREE팀의 meow_love, 카이스트 Entropi 팀, Rock kokiri Paper 팀의 cywohoy와 저녁을 먹었습니다. 제가 앉은 테이블에는 저와 서울대학교 4명이 앉았는데, 서울 리저널이 열리는 지역의 지역명을 딴 대학이므로 서울대학교라는 드립을 쳤던 기억이 있습니다. 서로 잘 알고 지내는 사이여서 테이블에서 늘 있는 WWE만 오갔던 것 같습니다. 이 날도 이슈가 있었습니다. 벡스코 인근 섬식버스정류장에 익숙하지 않았던 나머지 6729skl과 같이 반대로 가는 버스를 타고 말았습니다. 빠르게 눈치채 별 문제없이 반대 방향으로 갈아탈 수 있었습니다.

 

기본 전략은 천천히 따라가자 였습니다. 초반 패널티가 중요한 템포는 아니라고 생각했기 때문에 조금 더 천천히 봐도 된다고 생각했고, 빨리 풀지 않아도 솔브 수가 높으면 그만한 보상이 될만한 셋이라고 생각했습니다. 초반 10분동안은 스코어보드를 천천히 보기만 하면서 문제 분석을 시도했습니다.

 

문제 순서대로 문제지를 배분한 것이 실책이었던 것 같습니다. 결과적으로 큰 이슈가 되지는 않았으나 문제를 셔플해서 분배하는 것도 전략이 될 수 있겠다 싶었습니다. 초반 빠른 타이밍이 6729skl이 L의 풀이를 가지고 왔습니다. 저와 풀이를 함께 검토하는 동안 kolorvxl이 스코어보드를 보고 M번을 읽기 시작했고, M의 풀이가 훨씬 간단해 먼저 구현했습니다.

이후 L을 두 번이나 틀렸습니다. y와 l,r의 제한 차이가 있음을 놓쳤던 것을 빠르게 확인하고 구현을 수정해 맞았습니다.

 

2솔브 30위로 올라간 뒤 스코어보드를 확인 후 바로 G를 확인했습니다. G의 부담스러운 삽화를 뒤로 하고 아마 30분 안되어 풀이를 금방 찾았던 것 같습니다. 풀이를 정리하는 동안 kolorvxl이 C를 읽고 구현했던 것 같습니다. 결국 둘 다 WA를 받았습니다. G를 구현하는 동안 C를 디버깅에 성공해 3솔브로 올라가던 중에 G에서 추가로 5패널티를 받았습니다.

6729skl이 코드를 읽고 디버깅을 하면서 제가 D,E를 읽었습니다. 뭣도 안되는 전략이라고 생각하긴 하나 G를 계속 보면 터널 비전에 빠져버릴 것만 같아서 눈을 좀 돌렸습니다. 결국 C에서 AC를 받은 118분부터 E를 맞은 179분까지 G에 저와 6729skl이 묶여 있었고 kolorvxl도 머리식히느라 잠시 쉬던 탓에 팀 전체가 물려버리는 사태가 벌어졌습니다. 이 시점까지 상당히 절망적인 결과라 할 수 있을 것 같습니다.

 

kolorvxl에게 E를 설명해 주고 다시 G로 돌아왔습니다. 스코어보드를 보나 체감을 보나 분명 G는 구현에 말려 못 풀고 있던 것이었고, 다른 문제를 풀어도 결국 G를 풀어야한다는 압박감이 심해졌습니다. kolorvxl이 E를 해결해 구현하는 동안 저와 6729skl는 코드를 다시 뒤집어 엎는 최후의 선택을 하게 되고, 6729skl이 처음부터 코드를 작성해 AC를 받을 수 있었습니다. 최종 해설때 오버플로에 유의해서 작성해야할 수 있었다는 말에 6729skl이 거의 몇시간동안 보고 있던 의미는 있었다고 했지만 여전히 두 사람을 묶어둔 잘못이 크다고 생각합니다.

 

이제 남은 문제는 D를 풀어내고 I를 해결하는 것이었습니다. D는 제가 보던 문제였기 때문에 제가 계속 읽고, I를 kolorvxl이 읽었습니다. G번의 여파로 더이상 코드를 구현할 수 없는 상황이 되어 kolorvxl에게 풀이를 대충 설명했습니다. D를 kolorvxl이 어떻게든 차력쇼로 구현했던 것 같습니다. 그리고 나온 말이 I가 개레전드구현비빔밥이라는 것이었습니다. I를 구현하는 동안 더 뭔가 풀기는 어려울거라 생각하고 낮은 7솔브 마무리를 예상했습니다. 

 

그런데 대회장 분위기가 심상치 않습니다. K가 생각보다 할만해보였고, 웅성웅성하면서 불도저가 들렸습니다. 6729skl이 UCPC2025의 매내처를 보는 듯했다고 했습니다. K를 읽자 마자 각도 정렬 후 정렬 순서에 따른 스위핑이 필요할 것이라고 바로 짐작하고, 불도저를 비벼서 푸는 풀이를 만들어냈습니다. I 구현을 끝낸 kolorvxl을 붙잡고 구현하라고 주장했습니다. 이미 G번에서 큰 패널티를 받았기 때문에 8솔 최하위인 Endgame보다 이미 패널티 수치가 높았고, 8솔브로 올라가더라도 수상은 어려운 상황이었습니다. kolorvxl이 네 포인터 돌리기라는 똑붙 구현을 했고, 제가 외우고 다니는 각도 정렬 구현으로 정렬에 막히지 않아 294분에 겨우 K를 풀어내는 데 성공해 23위로 올라갔습니다. 이후 CPG와 2beatdown에 역전을 허용해 25위로 마무리했습니다.

 

단연 이번 셋에서 가장 잘못한 점이라면 G를 구현하는 데 두 명이나 스턴 걸어놓고 한 시간 넘게 아무 것도 못한 것이라고 할 수 있습니다. 물론 결과적으로 패널티 관리를 잘 했으면 20등 이내에 비벼지기도 하거니와 H도 어떻게 비벼봄직 했겠다마는 결과를 떠나서 퍼포먼스가 가장 안좋았던 타이밍이기도 해 많은 아쉬움이 있습니다. 

 

대회가 끝나고 전북대학교 2 3 5 8 14의 iluem100, 전남대학교 PIMM팀, kolorvxl이 저녁을 먹었습니다. 대회가 마무리 되고 대회의 여운, 아쉬움으로 인한 스턴, 약간의 업무얘기를 이유로 거의 마지막까지 남아있었던 것 같은데 똑같은 상황의 iluem100과 저녁 파티를 만들게 되었습니다. 모든 파티 멤버는 iluem100이 모아왔습니다. 앳코더 쳐야한다고 먼저 간 kolorvxl을 제외하고 가장 가까운 저는 그렇다 치더라도 마지막까지 남아있던 0do, iluem100은 잘 돌아갔는 지도 잘 모르겠습니다. 2 3 5 8 14는 마닐라도 무사히 다녀왔으니 잘 들어간 셈 치기로 했습니다.

 

어쩌다보니 아주 운이 좋게도 69시드로 APAC에 진출하게 되었습니다. Endgame이 마닐라 리저널을 우승한다면 같은 경우의 수를 내심 신경쓰고 있었는데 그런 복잡한 계산 없이 바로 가게 될줄은 생각하지도 못한 결과였습니다.

아무래도 다시는 없을 APAC 기회라고 생각하니 심기일전하게되는 것 같습니다. 아무래도 이번 팀이 올해도 저만 남게 될 것 같고 다시 없을 전력이라 생각됩니다. 단순히 아챔 가봤다도르로 끝나지만 않았으면 좋겠습니다.

'Problem solving' 카테고리의 다른 글

Atcoder Educational DP Contest 풀이 요약  (0) 2026.06.08
Good Bye, BOJ 2025! 후기  (0) 2026.02.23
ICPC 2025 Seoul Regional Nationwide Copetition 후기  (0) 2025.12.30
BOJ 18457 Knowledge  (2) 2025.08.02
ICPC 2024 Regional Seoul 후기  (2) 2025.07.17

ICPC 2025 서울 리저널 인터넷 예선이 끝났습니다. 끝난지는 한참 됐는데 그래도 해 바뀌기 전에 후기는 써야할 것 같아 급히 작성합니다.

 

Just Reboot JungSangHwa라는 팀명으로 출전했습니다. 이상한 뜻이 있는게 아니고 ICPC 2024의 팀 JungSangHwa를 리부트해서 새롭게 멤버를 짜왔다는 의미입니다. 

 

qvixnh22: 2024 JungSangHwa 팀에서 유일하게 남은 팀원입니다. 논증기하, 그래프, 직관에서 증명으로 넘어가기에 상대적으로 강하고 구현에 아주 약합니다. 이 부분은 본선에서 아주 크게 작용합니다.

6729skl: 2024 LeetTtukBang 팀 멤버입니다. LeetTtukBang의 mbae059와 Yera_가 졸업을 하는 바람에 혼자 남겨졌습니다. 팀에서 개발 경력이 가장 길기 때문에 디버깅에 강합니다. 하지만 이 부분도 본선에서 크게 작용합니다.

kolorvxl: 25학번 신입생(였던 것)입니다. 코드포스 레이팅이 높은 만큼 구현 실력이 팀에서 가장 좋습니다. 로직 이해가 어려운 편인 문제의 구현을 전적으로 맡았습니다.

 

대회 직전까지 본선 진출에 대해서는 아무 걱정이 없었습니다. 부산대학교 팀 역사상 가장 강력하다고 추정되는 수준의 팀이 나왔다싶기도 했고, 학교 1등으로 단독 진출을 노리기에 다른 팀들에 비해서 실력 차이가 충분히 난다고 판단했기 때문입니다.

 

천천히 시작했습니다. 2024 예선때와 마찬가지로 교내 전체 참가자가 강의실에 모여서 컨테스트를 진행했고, 또 마찬가지로 문제지가 빠르게 도착하지 않았기 때문에 문제지를 모니터로 가장 먼저 확인했습니다.

 

문제지를 순서대로 나눠 가지고 문제를 읽었습니다. 제가 A~D, kolorvxl이 E~G, 6729skl이 H~J를 받았던 것 같습니다. 앉아있는 순서대로 문제지를 나눠 가졌습니다. 

제가 가장 먼저 잡은 문제는 A입니다. (기억은 안나는데 kolorvxl이 제가 A를 풀었다고 했습니다.) 범위를 보자마자 배열 A와 배열 B를 공통으로 사용하는 DP가 가장 먼저 떠올랐지만 여러가지 생각해보니 dp 포인터가 대각선에서만 움직이므로 선형 dp로 해결가능함을 관찰했습니다. (아마 그랬을겁니다.) 그래서 dp update가 선형 시간에 돌아도 됨을 확인하고 선형 시간에 동작하는 dp update 로직을 찾았습니다.

 

그 와중에 kolorvxl이 F를 빠르게 읽고 빠르게 구현했습니다. 실제로 전체 문제 중 가장 쉬운 문제였습니다. 그리고 시작한 지 7분만에 WA를 받았습니다.

F를 일단 6729skl이 디버깅하기로 하고 제가 A를 구현해 14분만에 AC를 받았습니다. I가 정수론이고 제가 팀에서 정수론을 가장 잘한다는 팀원들의 일방적인 주장에 따라 I를 고민하고 있었습니다.

 

kolorvxl이 I를 같이 고민하는 동안 6729skl이 F의 leading zero 반례를 하나 찾았습니다. 찾은 시점에 이게 마지막 남은 반례가 맞는 지 토의했습니다. 제가 세 번 고민 끝에 제출하자고 했고 18분에 AC를 받았습니다. 이 시점에서 13위까지 올라갔기 때문에 예상 이상으로 좋은 성적을 받을 수 있으리라 생각했습니다.

 

결국 I 풀이를 내기까지 오랜 시간이 걸렸습니다. 아무래도 근을 먼저 정해 두고 전개하는 관찰이 좋지 않았던 것 같습니다. 상수항이 이미 인수분해가 한 번 이상 된 꼴이라 더 말린 것 같습니다. kolorvxl이 근의 공식으로 가면 좋겠다고 한 뒤로 쉽게 해결되었습니다. 근의 공식을 쓰니 p가 가져야 할 restriction이 바로 보였습니다. p(p-4k)가 완전제곱이기만 하면 된다는 점을 바로 관찰했고, kolorvxl이 디테일을 챙겨 구현해 50분에 AC를 받았습니다. 다르게 식을 정리할 것 없이 p(p-4k)가 완전제곱인지만 봐도 충분했을 것 같습니다.

근의 공식 이전에 대칭이므로 개수만 알면 합은 쉽게 구할 수 있음을 알았지만 모든 경우를 탐색하는 것으로 개수를 알아내는 방법을 선택해 의미가 없었습니다.

 

I를 구현하는 동안 H를 읽었습니다. UCPC2024의 "산을 그리세요"와 비슷한 감성으로 dp를 챙겨보려 했습니다. 제법 오래 고민했던 것 같은 기억이 있으나 H를 언제부터 읽었는지 기억나지 않습니다. I의 AC 이후 kolorvxl과 함께 H를 고민했는데 제가 다른 문제를 잠시 보고 오는 사이 45도 돌리면 LIS가 되는게 아니냐는 풀이가 나왔습니다. 10초정도 보니 formal proof가 바로 보여서 kolorvxl이 구현을 시작했습니다. 6729skl과 함께 J를 읽었던 것 같습니다. 그 와중에 이분 탐색을 짜고 있길래 팀노트에 LIS 구현이 있다고 해서 빨리 구현을 완료할 수 있었습니다. 63분에 AC를 받았습니다.

 

H를 구현하는 동안 6729skl이 J를 읽고 그래프 모델링이 끝난 버전으로 설명해줘서 함께 고민했습니다. 기억하기로는 비슷한 유형의 문제를 연습 중에 깨달았던 것 같습니다. 2-path의 모임을 관리하면 200만개 이하의 에지만 관리해도 됨을 함께 관찰했습니다. 다만 degree 제곱의 합만큼 돌아야했는데 O(m^2)이 아닐까 하고 고민을 했습니다. 지금 생각하니 O(nm)에 바운드되는데 왜 관찰하지 못했나 싶습니다. kolorvxl이 구현했던 것 같고 67분에 AC를 받았습니다.

 

그리고 혼자 B로 넘어가고 팀원들이 C를 어떻게 잘 풀어왔습니다. C는 아직 풀이도 뭐도 잘 모릅니다. B,D,E를 번갈아 보며 뭐가 쉬운지 가늠했던 것 같습니다. 결국 B는 제가 문제를 잘못 읽어 예제가 왜 저렇게 나온지도 이해하지 못하고 마무리했고, E는 하나를 시간 축으로 삼는 구간쿼리 문제임을 짐작했지만 오프라인 쿼리를 써볼 생각을 하지 못했고, 마지막으로 D의 구성을 조금 생각해봤으나 결국 찾지 못했습니다. 

 

최종 스코어 6솔브 16등으로 마무리했습니다. 

진짜 중요한 얘기는 본선에서 나옵니다.

'Problem solving' 카테고리의 다른 글

Good Bye, BOJ 2025! 후기  (0) 2026.02.23
ICPC 2025 Seoul Regional Competition 후기  (1) 2026.01.08
BOJ 18457 Knowledge  (2) 2025.08.02
ICPC 2024 Regional Seoul 후기  (2) 2025.07.17
UCPC2024 후기  (0) 2024.09.01

문제

You have a string s consisting of lowercase English letters “a” and “b”.

You can make zero or more operations in any order. Here are the possible operations:

  • Delete “aa” from any place of the string.
  • Delete “bbb” from any place of the string.
  • Delete “ababab” from any place of the string.
  • Add “aa” to any place of the string.
  • Add “bbb” to any place of the string.
  • Add “ababab” to any place of the string.

Your goal is to calculate the number of strings of length x that can be obtained by such operations. As the answer can be very large, find it modulo 998 244 353.

입력

The first line of the input contains one integer n: the length of the string (1 ≤ n ≤ 300 000).

The second line contains a string s of length n consisting of lowercase English letters “a” and “b”.

The third line contains one integer x (0 ≤ x ≤ 109), the length of the string you need to obtain.

출력

Print one integer: the number of strings of length x that can be obtained from string s by making the operations described above, taken modulo 998 244 353.

풀이

문자열에 "aaa", "bbb", "ababab"를 자유롭게 추가하고 제거할 수 있다. 이 작업이 항상 역연산이 가능하므로 equivalence class의 원소 개수를 세는 문제임을 알 수 있다.

free monoid의 equivalence class문제로 생각해보자. 이는 어떤 free monoid homomorphism의 kernel로 생각할 수 있고, 항등원 e, "aa", "bbb"가 같은 class로 대응되기 때문에 a의 위수가 2, b의 위수가 3인 군임을 알 수 있다.

 

이제 군 연산을 이용해서 class의 구조를 알아내면 된다. 이 구조가 군이기 때문에 right multiplicative automota는 Caley graph에 대응이 되고, 그래프를 손으로 열심히 그려보면 정점 12개의 regular directed graph를 얻을 수 있다.

 

마지막으로 우리가 구하고자 하는 것은 주어진 문자열과 같은 class의 원소이면서 길이가 x인 원소의 개수이므로 정확히 Caley graph에서 [e] class에서 시작하는 distinct walk의 개수이므로 인접행렬의 거듭제곱으로 얻을 수 있다.

 

주어진 문자열이 어떤 class에 속하는지 구분하는 방법은 여러가지가 있는데, 가장 쉬운 방법은 Caley graph가 automata인 점을 이용해 선형 시간에 어떤 클래스에 속하는지 추적하는 방법이 있고, 아니면 정말 단순하게 주어진 연산 중 문자열 길이를 줄이는 연산을 적절히 찾아 monotone deque를 이용해 문자열을 재구성하는 방법이 있다. 전자의 경우는 automata의 구조를 미리 가지고 있어야 하므로 구조를 이미 알고 있는 경우 적합하고, 후자의 경우는 일반적으로 사용할 수 있으나 이 구조가 유한 모노이드임을 모른다면 유한 시간에 끝나기 어려운 방법이다.

후자의 방법으로 문자열을 재구성하기 위해서 "aa"->e, "bbb"->e, "ababab"->e 외에도 "abba"->"bab", "aba"->"bbabb", "babba"->"bbab"의 3개의 연산을 추가로 사용했다. "aba"->"bbabb"는 문자열의 길이가 늘어나는 것이 아니냐고 생각할 수 있는데, automata의 구성 과정에서 얻어진 변환이라 정확한 근거는 모르겠지만 저렇게 변환하면 모든 class를 얻을 수 있었다.

 

추가로 이 군은 A4와 동형이고, 실제로 이 문제를 A4(isomorphic to PSL2Z3)임을 group representation <a,b|aa,bbb,ababab>만으로 알아내 해결한 사람도 있다. (링크) 하지만 group representation은 상당히 어려운 주제이고, 열심히 문자열을 분류하는 것이 가장 쉬운 방법이 아닐까 싶다.

2025년이 되었지만 아직까지 작성하지 않고 미뤄 둔 ICPC 2024 Regional Seoul 후기글입니다.

 

2024년도는 전역 후 복학한 첫 해였다. 2021년 입학 당시 리저널에 대한 정보가 없어 참가하지 못했고, 복학한 뒤 열린 첫 ICPC였기 때문에 첫 ICPC 참가가 되었다. 2024 PNUPC 운영진으로 참가한 것을 계기로 Pulse에 가입하게 되었고, Pulse 내에서 팀을 구성하려 한 끝에 어찌저찌 팀이 만들어졌다.

 

이 팀명은 나중에 네임드가 됩니다.

팀명을 정하는 과정이 아주 멀고 힘들 것이라고 생각했지만 상당히 재밌는 아이디어가 나왔다. 마침 고려대학교 MatKor Cup에 제출된 @pizzaroot님의 코드가 아주 잠깐 화두에 올랐기도하고 해서 만장일치로 팀명은 JungSangHwa가 되었다. (정상화 교수님 수업은 아주 좋았습니다)

 

팀 연습 퍼포먼스가 좋지 않아 고민이 많았던 것 같다. 요코하마 리저널을 돌았던 것 같은데 지금 보면 다소 초라한 성적이 아닌가 생각한다.

 

 

지금 돌아보면 예선 결과가 마냥 좋지 않다.

 

E (+1, 00:11) 차분 행렬의 최대값을 찾는 문제로 환원가능했다. 상당히 괜찮은 관찰이었기 때문에 제일 먼저 구현했다. 빠르게 AC를 받을 뻔했으나 늘 그렇듯 구현이 말썽이었다. 패널티를 받은 이유는 기억나지 않는다.

 

H (+3, 01:37) 간단히 모든 경우를 다 시도해볼 수 있었다. @corn_tufu가 구현했다. 백트래킹으로 구현하다가 구현을 실수한건지 패널티를 크게 받았다. 물론 구현 시간도 많이 지났다. 그 사이 D/F번을 읽었다. 대회가 끝나고 복기할 때 백트래킹하지 않고 그냥 나이브 브루트포스로 할 수 있는거 아니냐며 질책했다. 쉬운문제를 돌아가면 큰일난다.

 

F (+1, 02:18) 그림에서 피자 정리가 생각난다. 항상 binary planar decomposition이 된다는 점을 관찰하는 것으로 시작했다. 선분의 정보가 상당히 곤란하게 주어졌다. point in polygon을 하듯 점의 패리티를 세는 풀이를 냈으나 상당히 구현에 어려움을 겪으리라 생각했다. @corn_tofu가 구현했다. 열심히 구현해서 AC를 받은 것 같은데 어떤 실수였는지 기억나진 않지만 사소한 실수 하나를 해 패널티를 받았던 것 같다.

 

D (0) 풀이는 상당히 빨리 나왔다. @light_potato가 그리디하게 내려가는 풀이를 만들었으나 다른 문제 구현하느라 구현하지 못했던 것으로 기억한다. 실제 구현 시도도 했으나 잘 구현되지 않았던 것 같다. 2-sat 풀이도 생각했으나 결국 그리디가 맞았다.

 

C (-10) 열심히 구현했다. 완성된 문자열을 지우는 문제로 환원하면 긴 접두사를 지우게 되면 더 적은 비용으로 해결할 수 있는 점에 착안해서 열심히 구현했으나 AC를 띄우지 못했다.

 

다른 문제도 보긴 했는데 잘 기억나지 않는다.

 

스코어보드정상화

하지만 C의 테스트케이스에 문제가 있었음을 공지받았고, 재채점 결과 60등까지 올라갔다. 사실 맞는 풀이였는지도 모르겠다. 아무튼 맞았으니까 된거 아닐까 싶었고, 리저널 본선에 가게 되었다.

 

 

A (+1, 01:23) 첫 솔브까지 상당히 오래 걸렸다. 엄청 어려운 문제가 아니었는데 구현에서 절었다. 경계값 같은 구현 디테일에서 상당히 죽을 쒔던 것 같다.

 

L (02:24) 상당히 빠른 시기에 풀이를 내고 @corn_tofu에게 구현을 요청했다. 무난하게 AC. 하지만 증명하느라고 구현을 늦게 시작했다. 증명까지 해줬어야했을까 싶다.

 

B (+2, 03:22) 그래프 문제임을 알아내는 데 한세월이 걸렸다. 문자열 문제로 단단히 착각하고 감을 잡는데 상당히 멀리 돌아 갔다. 동적으로 그래프탐색을 하면서 답을 찾는 풀이를 먼저 냈는데 구현을 시작하자마자 컴포넌트 크기로 해결할 수 있음을 깨달았다. 패널티를 받은 이유는 기억나지 않는다.

 

L (-5) 시뮬레이션 결과로 이분 탐색한다는 사실은 아주 빠르게 알아냈지만 구현이 잘못됐는지 AC를 받을 수 없었다. @light_potato가 구현했다. 이 문제에 들인 구현 노력 때문에 오히려 다른 문제를 보고 구현할 시간이 모자랐다.

 

D (-5) 이런 문제를 잡았었나?

 

F (0) 그냥 하면 된다는 사실을 깨닫는데는 오래 걸리지 않았는데, 수상한 바운드와 제한 안에 들여보낼 방법을 고민하다가 결국 풀지 못했다. 다시 풀어볼만한 문제인 듯하다.

 

모든 문제를 풀고 나서 퇴실 직전 남는 시간에 앞자리에 앉은 제주대학교 MerVermillon팀과 인사를 나눴다. 똑같이 아주 멀리서 왔기 때문에 동질감이 들었다.

 

모든 행사를 마치기 전에 먼저 귀가했다. 장거리 일정이어서 컨디션 관리에 실패한 것도 있고 여러 이유로 먼저 갔다. @mbae059가 다시 돌아오라고 했지만 버스를 타고 이미 떠난 시점이었다. 

 

https://youtu.be/_af5H9iqzDo?feature=shared

 

 

많은 분들이 관심을 가져주셨던 팀명이 유튜브를 탔다. (...)

이 영상이 올라오고 많은 분들이 연락해오셨다. 내년에는 더 재밌는 팀명으로 찾아뵙겠습니다. 감사합니다.

+ Recent posts