Jekyll2022-09-10T19:55:19+00:00https://justicehui.github.io/rss/JusticeHui가 PS하는 블로그Let's solve problem with JusticeHui!JusticeHuiICPC Sinchon 2022 Summer Algorithm Camp 강의 후기2022-09-10T00:00:00+00:002022-09-10T00:00:00+00:00https://justicehui.github.io/review/2022/09/10/icpc-sinchon<h3 id="서론">서론</h3> <p>신촌지역 대학교 프로그래밍 동아리 연합 캠프에서 알고리즘 강의를 했습니다. 지금까지 강의 후기는 한 번도 안 적어봤는데 이번에는 적으면 몇 명 선정해서 상품을 준다고 해서(…) 적어보려고 합니다.</p> <h3 id="icpc-sinchon-관련-이야기">ICPC Sinchon 관련 이야기</h3> <p>이전에도 ICPC Sinchon과 함께 일을 한 적이 있습니다. 2년 전 여름, shiftpsh님의 제안으로 ICPC Sinchon의 첫 대회인 SUAPC 2020의 검수진으로 합류하게 되었습니다. 그때 당시에 처음 만들어진 연합임에도 불구하고 운영이 매끄럽고 대회 퀄리티도 좋았던 것으로 기억합니다. 그 뒤로도 대회 검수 요청이 몇 번 오긴 했지만 시간이 안 맞아서 ICPC Sinchon과는 연이 닿지 않았습니다.</p> <p>저는 보통 1주일에 한 번 정도 <a href="https://www.acmicpc.net/board/list/ad">BOJ 홍보 게시판</a>을 확인합니다. 게시판을 둘러보던 도중 <a href="https://www.acmicpc.net/board/view/92046">ICPC Sinchon 강사 모집 글</a>을 보았고, 무급으로 일하는 숭실대 동아리보다는 낫다는 생각에 지원을 했습니다. 지원할 때 강의 영상을 제출해야 하는데 이건 몇 달 전에 SCCC에서 강의했던 영상을 제출했습니다. 영상을 보고 판단한 건지 BOJ 핸들을 보고 판단한 건지 모르겠지만, 아무튼 강사 합격 연락을 받게 되었습니다. 제출한 영상이 별로 마음에 드는 영상은 아니었는데 좋게 봐주신 것 같습니다.</p> <h3 id="강의-구성">강의 구성</h3> <p>이번 캠프는 초급반과 중급반으로 나눠져 있었으며 저는 <a href="https://www.acmicpc.net/user/jjaewon9">jjaewon9</a>와 함께 중급반을 맡았습니다. 커리큘럼은 제가 직접 구성했습니다. 캠프 운영진 측에서 과거 캠프 커리큘럼을 제공해 줬는데, 너무 사전 지식을 가르치는 것에 치우친 것 같아서 처음부터 다시 짰습니다. 구성은 다음과 같습니다.</p> <ul> <li>기본기 훈련 <ul> <li>분할 정복</li> <li>세그먼트 트리</li> <li>모노톤 큐/스택</li> <li>DP 1 (위상정렬, 트리, 구간, 기댓값 등)</li> <li>DP 2 (그리디+DP, 게임이론, 자료구조 등)</li> </ul> </li> <li>다양한 주제 찍먹 <ul> <li>기초 정수론 (확장 유클리드, 페르마 소정리, 중국인의 나머지 정리 등)</li> <li>트리 (오일러 투어 테크닉, 스파스 테이블, LCA)</li> <li>그래프 (DFS Tree, SCC, 2-SAT)</li> <li>문자열 (해싱, 트라이, KMP)</li> </ul> </li> </ul> <p>사전 지식은 쉽게 공부할 수 있고, 수강생들의 평균적인 실력을 봤을 때 Network Flow나 Sprague Grundy Theorem 같은 어려운 사전 지식을 가르칠 필요는 없을 것 같아서 solved.ac 기준 알고리즘 기본 티어가 플래티넘 3 이상인 내용은 모두 배제했습니다. 대신 기본적인 내용을 잘 활용할 수 있도록 내용을 구성하는 데 초점을 맞췄습니다.<br /> 하지만 사전 지식을 안 가르치고 문제 풀이만 계속 시키면 재미없을 수 있기 때문에, PS의 다양한 토픽(수학, 그래프 이론, 문자열 등)을 공부할 때 기본이 되는 내용도 몇 개 추가했습니다. 기하도 넣고 싶었지만 시간이 안 돼서 넣지 못했습니다.<br /> 이렇게 열심히 고민해서 만든 커리큘럼인데 수강생분들께 제 의도가 잘 전달되었는지는 모르겠습니다.</p> <p>원래 위에 있는 순서로 진행하려고 했지만 조금 달라졌습니다. 캠프 운영진 측에서 두 강사가 홀수 번째 회차와 짝수 번째 회차로 나눠서 진행하라고 해서 순서를 조금 수정했습니다. 최종적으로 확정된 커리큘럼은 <a href="https://icpc-sinchon.io/halloffame">ICPC Sinchon 공식 사이트</a>에서 확인할 수 있습니다.</p> <h3 id="강의-준비">강의 준비</h3> <p>ICPC Sinchon 외에도 삼성전자, SSAFY, 선린인터넷고등학교, 숭실대학교 등 여러 곳에서 강의를 했었고, 강의를 하면서 만든 자료가 많이 쌓여 있습니다. 사실 강의 자료 재탕하면서 날로 먹을 생각으로 강사 지원을 했지만… 예전에 만든 자료가 마음에 들지 않거나 처음 강의하는 내용이라서 대부분의 슬라이드를 새로 만들게 되었습니다.</p> <p>매 회차 슬라이드를 만드는 데 12시간 이상 걸렸던 것으로 기억합니다. 강사비가 회당 7만원이었으니까… 최저 시급의 절반만 받으면서 일한 것 같습니다. 한 번 쓰고 버리는 건 너무 아까우니까 나중에 재탕할 일이 생겼으면 좋겠습니다. 자료는 <a href="https://github.com/justiceHui/SSU-SCCC-Study/tree/master/2022-summer-sinchon-adv">여기</a>에서 확인할 수 있습니다.</p> <h3 id="강의">강의</h3> <p>1~2달밖에 안 지났는데 벌써 기억이 가물가물해서 어떤 일이 있었는지만 간단하게 적습니다.</p> <h5 id="1회차---분할-정복-75">1회차 - 분할 정복 (7/5)</h5> <p>운영진 측에 강의를 7/5에 진행한다고 연락했지만 어찌 된 일인지 수강생들에게는 7/8이라고 공지되었습니다. 일정이 잘못 공지했다는 것을 강의 시작 15분 전에 깨달아서 상황도 어수선한데, 운영진은 “강사 개인 사정으로 일정이 변경되었다” 라고 공지를 하며 제 탓으로 돌리길래 화나서 때려치고 싶다는 생각이 들었습니다. 결국 저는 7/5에 강의를 진행하고 7/8에 강의 영상 녹화본을 제공하는 것으로 마무리되었습니다.</p> <p>원래 이 내용은 재귀 파트와 분할 정복 파트가 별개의 강의로 설계되어 있었지만 ICPC Sinchon에서는 한 강의에서 모두 다뤄서 강의가 조금 길어졌습니다. 그래도 수강생분들이 PS를 어느 정도 공부했던 분들이라 잘 따라오신 것 같습니다.<br /> 다양한 이야기를 했지만 결국 모든 이야기는 <strong>재귀함수 = 귀납법</strong>이라는 이야기로 귀결됩니다. 똑같은 말을 1시간 20분 동안 했는데 지루하지 않았을지 걱정됩니다. 속도가 조금 빨랐다는 피드백을 들었습니다.</p> <h5 id="3회차---모노톤-스택큐-722">3회차 - 모노톤 스택/큐 (7/22)</h5> <p>모노톤 큐를 사용하는 좋은 문제들은 대부분 DP와 엮여 있어서 문제를 고르는데 어려움이 있었습니다. 모노톤 스택도 맨날 나오는 오큰수, 히스토그램 말고 다른 문제를 찾기 위해 열심히 뒤졌습니다. 3회차는 문제를 고르기 어려웠던 것이 가장 기억에 남습니다.</p> <p>1회차는 줌, 3회차는 유튜브 스트리밍으로 진행했는데 유튜브는 딜레이가 너무 심하다는 피드백을 들었습니다. 5회차부터 계속 줌을 사용했습니다.</p> <h5 id="5회차---정수론-729">5회차 - 정수론 (7/29)</h5> <p>강의를 하려고 했는데 집 에어컨이 고장 나서 급하게 스터디 카페를 예약해서 강의를 진행했습니다.</p> <p>평소에 정수론 관련 알고리즘은 블랙박스로 써와서 강의 자료를 만들면서 같이 공부했습니다. 덕분에 지금은 원리를 이해해서 팀노트 없이 짤 수 있습니다. 역시 최고의 공부 방법은 강의인 것 같습니다.</p> <h5 id="7회차---문자열-85">7회차 - 문자열 (8/5)</h5> <p>1~5회차는 예전에 선린에서 강의했던 자료가 조금씩은 남아 있어서 설명 순서를 구성하는 노력은 안 해도 됐는데, 문자열은 아예 처음 하는 파트라서 강의 준비하는 데 훨씬 오래 걸렸습니다. 그리고 트라이 그림 그리는 것과 해싱 파트에서 파워포인트 수식 입력하는 것도 너무 귀찮았습니다.</p> <p>오토마타 관련 내용을 배제하고 직관에 의존해서 KMP를 이해시키기 위해 노력했는데 수강생분들이 잘 이해하셨을지 모르겠습니다. 강의 도중에 질문이 없는걸 보면 잘 이해한 게 맞겠지?</p> <h5 id="9회차---그래프-이론-812">9회차 - 그래프 이론 (8/12)</h5> <p>목이 아파서 슬라이드만 업로드하고 실시간 강의는 진행하지 않았습니다. 이 파트도 예전에 사용했던 자료가 없어서 슬라이드를 만드는 데 오래 걸렸습니다.<br /> 강의 자료 만들 때 주제를 착각해서 10회차 자료도 함께 만들었습니다. 깃허브 레포에 10회차 슬라이드가 있는 이유입니다.</p> <h5 id="11회차---문제-풀이-819">11회차 - 문제 풀이 (8/19)</h5> <p>마지막 회차는 지금까지 배운 내용을 이용해 다양한 문제를 풀어보는 시간입니다. 제가 좋아하는 문제들을 푸짐하게 넣을 수 있는 유일한 기회라서 마음껏 넣었습니다. 강의할 때도 신나서 떠들다 보니 2시간이 훌쩍 지나 있었습니다. 풀이만 대충 설명하는 것이 아니라, 어떤 사고 과정을 거쳐서 풀이를 냈는지 설명하는 것에 초점을 맞췄습니다.</p> <h3 id="camp-contest">Camp Contest</h3> <p>Camp Contest는 참가하지 않으려고 했지만 강사로서 참가하는 게 예의일 것 같아서 Open Contest에서 몇 문제 풀었습니다. 그냥 풀면 재미없을 것 같아서 뒤에서부터 풀기 시작했는데 3번째 문제에서 first solve를 뺏겨서 그만뒀습니다.<br /> 흔히 웰노운이라고 부르는 기법들이 많이 출제된 educational한 대회였습니다. 최근에 누가 <strong>“기본기 = 쉽고 뻔한 문제를 쉽고 뻔하게 푸는 능력”</strong> 이라고 이야기하는 걸 들었는데, 이 말을 생각하면 캠프 목적에 딱 맞는 대회인 것 같습니다.</p> <h3 id="suapc">SUAPC</h3> <p>Open Contest는 귀찮아서 참가 안 하고 나중에 버추얼 형식으로 풀었습니다. 본대회 1등팀이 11문제 풀었길래 혼자서 1등팀 이겨보려고 열심히 풀었지만 아쉽게도 이기지 못했습니다. E 풀이를 너무 늦게 찾은 게 원인인 것 같습니다.</p> <h3 id="마무리">마무리</h3> <p>개인적으로 강사 2명일 때 홀수 짝수 회차 제한이 있는 게 불편했습니다. 모집할 때부터 미리 공지하거나 정해진 횟수 안에서 자유롭게 조절할 수 있으면 좋을 것 같습니다. 그리고 차시 당 7만원은 강의 준비 시간까지 포함하면 최저 시급 절반밖에 안 되는 너무 적은 금액입니다. 다음 캠프부터는 강사비를 늘리면 더 좋지 않을까… 생각합니다.</p> <p>어떻게 끝내야 하지?</p>JusticeHui서론 신촌지역 대학교 프로그래밍 동아리 연합 캠프에서 알고리즘 강의를 했습니다. 지금까지 강의 후기는 한 번도 안 적어봤는데 이번에는 적으면 몇 명 선정해서 상품을 준다고 해서(…) 적어보려고 합니다.2022 SCPC 1차예선/2차예선 풀이 및 후기2022-08-06T00:00:00+00:002022-08-06T00:00:00+00:00https://justicehui.github.io/review/2022/08/06/scpc-qual<h3 id="서론">서론</h3> <p>본선 떨어지면 창피할 것 같아서 1차 예선 후기도 안 올렸는데, 다행히 본선 진출할 것 같아서 1/2차 후기를 함께 올립니다.</p> <p>점수는 다음과 같습니다.</p> <table> <thead> <tr> <th>번호</th> <th>1차 예선</th> <th>점수</th> <th>2차 예선</th> <th>점수</th> </tr> </thead> <tbody> <tr> <td>1</td> <td>개미</td> <td><strong>100/100</strong></td> <td>수열연산</td> <td><strong>100/100</strong></td> </tr> <tr> <td>2</td> <td>K 등분</td> <td><strong>140/140</strong></td> <td>반 협동게임</td> <td><strong>150/150</strong></td> </tr> <tr> <td>3</td> <td>직교 다각형</td> <td><strong>140/140</strong></td> <td>ABC</td> <td><strong>200/200</strong></td> </tr> <tr> <td>4</td> <td>지우개</td> <td>0/190</td> <td>직사각형</td> <td><strong>250/250</strong></td> </tr> <tr> <td>5</td> <td>독립</td> <td>135/230</td> <td>황금 카드</td> <td>73/300</td> </tr> <tr> <td>총점</td> <td> </td> <td><strong>515/800</strong></td> <td> </td> <td><strong>773/1000</strong></td> </tr> </tbody> </table> <p>데스크탑에서 보시는 분들은 오른쪽 사이드바를 활용하시면 원하는 문제로 쉽게 이동하실 수 있습니다.</p> <h3 id="1차-예선">1차 예선</h3> <p>1차 예선답게 쉬운 문제들이 출제되었습니다. 첫째 날에는 1, 2번과 5번의 부분 문제만 풀었는데, 혹시 떨어질까 불안해서 다음날 3번을 추가로 풀었습니다.<br />5번을 읽자마자 <a href="https://www.acmicpc.net/problem/7907">BOJ 7907 Bytean Road Race</a>가 생각나서 싱글벙글하며 코드를 긁어서 제출했는데 만점이 안 나와서 슬펐습니다. 하지만 더 생각하기 귀찮아서 풀지 않았습니다. 4번은 풀이를 찾았지만 구현이 귀찮아 보여서 안 풀었습니다.</p> <h4 id="1-개미">1. 개미</h4> <p>정렬한 다음, 원래 $i$번째에 있던 개미와 정렬된 배열에서 $i$번째에 있는 개미의 차이를 모두 더하면 됩니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="k">using</span> <span class="n">ll</span> <span class="o">=</span> <span class="kt">long</span> <span class="kt">long</span><span class="p">;</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">P</span><span class="p">[</span><span class="mi">303030</span><span class="p">];</span> <span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">A</span><span class="p">[</span><span class="mi">303030</span><span class="p">];</span> <span class="kt">void</span> <span class="nf">Solve</span><span class="p">(){</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">P</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">first</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">second</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span> <span class="n">sort</span><span class="p">(</span><span class="n">A</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">A</span><span class="o">+</span><span class="n">N</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span> <span class="n">ll</span> <span class="n">R</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">R</span> <span class="o">+=</span> <span class="n">abs</span><span class="p">(</span><span class="n">P</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">-</span> <span class="n">P</span><span class="p">[</span><span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">second</span><span class="p">]);</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">R</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="kt">int</span> <span class="n">TC</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">TC</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">tc</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">tc</span><span class="o">&lt;=</span><span class="n">TC</span><span class="p">;</span> <span class="n">tc</span><span class="o">++</span><span class="p">)</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Case #"</span> <span class="o">&lt;&lt;</span> <span class="n">tc</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">Solve</span><span class="p">();</span> <span class="p">}</span> </code></pre></div></div> <h4 id="2-k-등분">2. K 등분</h4> <p>원소의 합이 0인 경우와 0이 아닌 경우로 나눠서 해결할 수 있습니다.</p> <p>원소의 합이 0인 경우는 Prefix Sum이 0이 되는 위치 중에서 K개를 선택하면 되므로 이항 계수를 이용해 쉽게 답을 구할 수 있습니다.</p> <p>원소의 합을 $S(\neq 0)$라고 합시다. 각 조각의 합이 모두 같도록 $K$개로 나눠야 하므로, 각 조각의 합은 $S/K$가 되어야 합니다. 따라서 $S\not\equiv 0 \pmod K$이면 답은 0이고, $S \equiv 0\pmod K$이면 DP를 이용해 답을 계산할 수 있습니다.</p> <p>각 조각의 합을 $s=S/K$라고 정의합시다. 첫 번째 조각까지의 누적합은 $s$, 두 번째 조각까지의 누적합은 $2s$, $k$번째 조각까지의 누적합은 $ks$가 되어야 합니다.<br />$D(k,i) := $ $k$번째 조각이 $i$번째 인덱스에서 끝나는 경우의 수라고 정의합시다. 모든 $k$에 대해, 실제로 계산해야 하는 인덱스의 총 개수는 최대 $N$개입니다. $D(k,\ast)$의 누적합을 구해 놓으면, 투 포인터 기법을 이용해 정답을 $O(N)$에 구할 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="k">using</span> <span class="n">ll</span> <span class="o">=</span> <span class="kt">long</span> <span class="kt">long</span><span class="p">;</span> <span class="k">constexpr</span> <span class="n">ll</span> <span class="n">MOD</span> <span class="o">=</span> <span class="mf">1e9</span><span class="o">+</span><span class="mi">7</span><span class="p">;</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">int</span> <span class="o">&amp;</span><span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">){</span> <span class="n">a</span> <span class="o">+=</span> <span class="n">b</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">a</span> <span class="o">&gt;=</span> <span class="n">MOD</span><span class="p">)</span> <span class="n">a</span> <span class="o">-=</span> <span class="n">MOD</span><span class="p">;</span> <span class="p">}</span> <span class="n">ll</span> <span class="nf">Pow</span><span class="p">(</span><span class="n">ll</span> <span class="n">a</span><span class="p">,</span> <span class="n">ll</span> <span class="n">b</span><span class="p">){</span> <span class="n">ll</span> <span class="n">res</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">for</span><span class="p">(;</span> <span class="n">b</span><span class="p">;</span> <span class="n">b</span> <span class="o">&gt;&gt;=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">a</span> <span class="o">=</span> <span class="n">a</span> <span class="o">*</span> <span class="n">a</span> <span class="o">%</span> <span class="n">MOD</span><span class="p">)</span> <span class="k">if</span><span class="p">(</span><span class="n">b</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="n">res</span> <span class="o">=</span> <span class="n">res</span> <span class="o">*</span> <span class="n">a</span> <span class="o">%</span> <span class="n">MOD</span><span class="p">;</span> <span class="k">return</span> <span class="n">res</span><span class="p">;</span> <span class="p">}</span> <span class="n">ll</span> <span class="n">N</span><span class="p">,</span> <span class="n">K</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="mi">505050</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">505050</span><span class="p">],</span> <span class="n">Fac</span><span class="p">[</span><span class="mi">505050</span><span class="p">],</span> <span class="n">Inv</span><span class="p">[</span><span class="mi">505050</span><span class="p">];</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">V</span><span class="p">[</span><span class="mi">505050</span><span class="p">],</span> <span class="n">D</span><span class="p">[</span><span class="mi">505050</span><span class="p">];</span> <span class="n">ll</span> <span class="nf">Comb</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">){</span> <span class="k">return</span> <span class="n">r</span> <span class="o">&lt;=</span> <span class="n">n</span> <span class="o">?</span> <span class="n">Fac</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">*</span> <span class="n">Inv</span><span class="p">[</span><span class="n">r</span><span class="p">]</span> <span class="o">%</span> <span class="n">MOD</span> <span class="o">*</span> <span class="n">Inv</span><span class="p">[</span><span class="n">n</span><span class="o">-</span><span class="n">r</span><span class="p">]</span> <span class="o">%</span> <span class="n">MOD</span> <span class="o">:</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">Solve</span><span class="p">(){</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span> <span class="o">&gt;&gt;</span> <span class="n">K</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">K</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">V</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">clear</span><span class="p">(),</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">clear</span><span class="p">();</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="k">if</span><span class="p">(</span><span class="n">S</span><span class="p">[</span><span class="n">N</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">){</span> <span class="kt">int</span> <span class="n">cnt</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cnt</span> <span class="o">+=</span> <span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">Comb</span><span class="p">(</span><span class="n">cnt</span><span class="p">,</span> <span class="n">K</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">S</span><span class="p">[</span><span class="n">N</span><span class="p">]</span> <span class="o">%</span> <span class="n">K</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">){</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="mi">0</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="n">ll</span> <span class="n">step</span> <span class="o">=</span> <span class="n">S</span><span class="p">[</span><span class="n">N</span><span class="p">]</span> <span class="o">/</span> <span class="n">K</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">%</span> <span class="n">step</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span> <span class="n">ll</span> <span class="n">q</span> <span class="o">=</span> <span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">/</span> <span class="n">step</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="mi">1</span> <span class="o">&lt;=</span> <span class="n">q</span> <span class="o">&amp;&amp;</span> <span class="n">q</span> <span class="o">&lt;=</span> <span class="n">K</span><span class="p">)</span> <span class="n">V</span><span class="p">[</span><span class="n">q</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> <span class="p">}</span> <span class="n">V</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="n">D</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">K</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">V</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">empty</span><span class="p">()){</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="mi">0</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">k</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">V</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">size</span><span class="p">();</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="k">while</span><span class="p">(</span><span class="n">k</span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="n">size</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">V</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">k</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">])</span> <span class="n">k</span><span class="o">++</span><span class="p">;</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">k</span> <span class="o">?</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">k</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">:</span> <span class="mi">0</span><span class="p">);</span> <span class="p">}</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">size</span><span class="p">();</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="n">Add</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">],</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">]);</span> <span class="p">}</span> <span class="kt">int</span> <span class="n">res</span> <span class="o">=</span> <span class="n">D</span><span class="p">[</span><span class="n">K</span><span class="p">].</span><span class="n">back</span><span class="p">();</span> <span class="k">if</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">K</span><span class="p">].</span><span class="n">size</span><span class="p">()</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">)</span> <span class="n">res</span> <span class="o">-=</span> <span class="n">D</span><span class="p">[</span><span class="n">K</span><span class="p">][</span><span class="n">D</span><span class="p">[</span><span class="n">K</span><span class="p">].</span><span class="n">size</span><span class="p">()</span><span class="o">-</span><span class="mi">2</span><span class="p">];</span> <span class="k">if</span><span class="p">(</span><span class="n">res</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="n">res</span> <span class="o">+=</span> <span class="n">MOD</span><span class="p">;</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">res</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">SZ</span> <span class="o">=</span> <span class="mi">500'000</span><span class="p">;</span> <span class="n">Fac</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">SZ</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">Fac</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">Fac</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">i</span> <span class="o">%</span> <span class="n">MOD</span><span class="p">;</span> <span class="n">Inv</span><span class="p">[</span><span class="n">SZ</span><span class="p">]</span> <span class="o">=</span> <span class="n">Pow</span><span class="p">(</span><span class="n">Fac</span><span class="p">[</span><span class="n">SZ</span><span class="p">],</span> <span class="n">MOD</span><span class="o">-</span><span class="mi">2</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="n">SZ</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&gt;=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">--</span><span class="p">)</span> <span class="n">Inv</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">Inv</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="n">MOD</span><span class="p">;</span> <span class="kt">int</span> <span class="n">TC</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">TC</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">tc</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">tc</span><span class="o">&lt;=</span><span class="n">TC</span><span class="p">;</span> <span class="n">tc</span><span class="o">++</span><span class="p">)</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Case #"</span> <span class="o">&lt;&lt;</span> <span class="n">tc</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">Solve</span><span class="p">();</span> <span class="p">}</span> </code></pre></div></div> <h4 id="3-직교-다각형">3. 직교 다각형</h4> <p>문제를 처음 보면 어려워 보이지만, 예제를 직접 그림으로 그려보면 풀이를 쉽게 찾을 수 있습니다.</p> <p>에러 점이 있는 행과 열은 홀수 개의 점을 갖고 있고, 그렇지 않은 행과 열은 짝수 개의 점을 갖고 있습니다. 그러므로 에러 점을 쉽게 검출할 수 있고, 남은 점들은 차례대로 2개씩 짝을 지어주면 됩니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; #define x first #define y second </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="k">using</span> <span class="n">Point</span> <span class="o">=</span> <span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span><span class="p">;</span> <span class="kt">void</span> <span class="nf">Solve</span><span class="p">(){</span> <span class="kt">int</span> <span class="n">N</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">X</span><span class="p">(</span><span class="n">N</span><span class="p">),</span> <span class="n">Y</span><span class="p">(</span><span class="n">N</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">x</span> <span class="o">&gt;&gt;</span> <span class="n">y</span><span class="p">;</span> <span class="n">X</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">Y</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">};</span> <span class="p">}</span> <span class="n">sort</span><span class="p">(</span><span class="n">X</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">X</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="p">[](</span><span class="k">const</span> <span class="n">Point</span> <span class="o">&amp;</span><span class="n">p1</span><span class="p">,</span> <span class="k">const</span> <span class="n">Point</span> <span class="o">&amp;</span><span class="n">p2</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">bool</span> <span class="p">{</span> <span class="k">return</span> <span class="n">make_pair</span><span class="p">(</span><span class="n">p1</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">p1</span><span class="p">.</span><span class="n">y</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">make_pair</span><span class="p">(</span><span class="n">p2</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">p2</span><span class="p">.</span><span class="n">y</span><span class="p">);</span> <span class="p">});</span> <span class="n">sort</span><span class="p">(</span><span class="n">Y</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">Y</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="p">[](</span><span class="k">const</span> <span class="n">Point</span> <span class="o">&amp;</span><span class="n">p1</span><span class="p">,</span> <span class="k">const</span> <span class="n">Point</span> <span class="o">&amp;</span><span class="n">p2</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">bool</span> <span class="p">{</span> <span class="k">return</span> <span class="n">make_pair</span><span class="p">(</span><span class="n">p1</span><span class="p">.</span><span class="n">y</span><span class="p">,</span> <span class="n">p1</span><span class="p">.</span><span class="n">x</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">make_pair</span><span class="p">(</span><span class="n">p2</span><span class="p">.</span><span class="n">y</span><span class="p">,</span> <span class="n">p2</span><span class="p">.</span><span class="n">x</span><span class="p">);</span> <span class="p">});</span> <span class="kt">int</span> <span class="n">xx</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">yy</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">=</span><span class="n">j</span><span class="p">){</span> <span class="k">while</span><span class="p">(</span><span class="n">j</span> <span class="o">&lt;</span> <span class="n">X</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">X</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">x</span> <span class="o">==</span> <span class="n">X</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">x</span><span class="p">)</span> <span class="n">j</span><span class="o">++</span><span class="p">;</span> <span class="k">if</span><span class="p">((</span><span class="n">j</span> <span class="o">-</span> <span class="n">i</span><span class="p">)</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="n">xx</span> <span class="o">=</span> <span class="n">X</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">x</span><span class="p">;</span> <span class="p">}</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">=</span><span class="n">j</span><span class="p">){</span> <span class="k">while</span><span class="p">(</span><span class="n">j</span> <span class="o">&lt;</span> <span class="n">Y</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">Y</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">y</span> <span class="o">==</span> <span class="n">Y</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">y</span><span class="p">)</span> <span class="n">j</span><span class="o">++</span><span class="p">;</span> <span class="k">if</span><span class="p">((</span><span class="n">j</span> <span class="o">-</span> <span class="n">i</span><span class="p">)</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="n">yy</span> <span class="o">=</span> <span class="n">Y</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">y</span><span class="p">;</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">xx</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="n">yy</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">){</span> <span class="n">X</span><span class="p">.</span><span class="n">erase</span><span class="p">(</span><span class="n">find</span><span class="p">(</span><span class="n">X</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">X</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">make_pair</span><span class="p">(</span><span class="n">xx</span><span class="p">,</span> <span class="n">yy</span><span class="p">)));</span> <span class="n">Y</span><span class="p">.</span><span class="n">erase</span><span class="p">(</span><span class="n">find</span><span class="p">(</span><span class="n">Y</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">Y</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">make_pair</span><span class="p">(</span><span class="n">xx</span><span class="p">,</span> <span class="n">yy</span><span class="p">)));</span> <span class="p">}</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">res</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">X</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">+=</span><span class="mi">2</span><span class="p">)</span> <span class="n">res</span> <span class="o">+=</span> <span class="n">abs</span><span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="n">y</span> <span class="o">-</span> <span class="n">X</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">y</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">Y</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">+=</span><span class="mi">2</span><span class="p">)</span> <span class="n">res</span> <span class="o">+=</span> <span class="n">abs</span><span class="p">(</span><span class="n">Y</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="n">x</span> <span class="o">-</span> <span class="n">Y</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">x</span><span class="p">);</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">res</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="kt">int</span> <span class="n">TC</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">TC</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">tc</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">tc</span><span class="o">&lt;=</span><span class="n">TC</span><span class="p">;</span> <span class="n">tc</span><span class="o">++</span><span class="p">)</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Case #"</span> <span class="o">&lt;&lt;</span> <span class="n">tc</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">Solve</span><span class="p">();</span> <span class="p">}</span> </code></pre></div></div> <h4 id="4-지우개">4. 지우개</h4> <p>연속한 a 그룹과 b 그룹을 묶은 다음, 양쪽 끝을 제외한 나머지 부분을 KMP로 매칭하면 되는 걸로 기억합니다.</p> <p>나중에 codeground에 문제가 올라오면 풀고 수정하겠습니다.</p> <h4 id="5-독립">5. 독립</h4> <p>Subtask 2(135점)는 <a href="https://www.acmicpc.net/problem/7907">BOJ 7907 Bytean Road Race</a>(<a href="/ps/2020/01/29/BOJ7907/">풀이</a>)를 풀고 inversion counting을 하면 $O(N^2 \log N^2)$에 해결할 수 있습니다.</p> <p>Subtask 3(230점)은 $O(N^2)$에 해결해야 합니다. 이 문제도 나중에 codeground에 문제가 올라오면 풀고 추가하도록 하겠습니다.</p> <h3 id="2차-예선">2차 예선</h3> <p>1, 2번은 쉬운 문제라서 빨리 풀었습니다. 각각 9시 10분, 9시 20분에 전체 참가자 중 13번째, 5번째로 풀었습니다.<br />3번은 풀이는 뻔한데 생각 정리가 잘 안 되길래 밥을 먹으면서 고민했습니다. 배열 크기를 너무 적게 잡아서 3번 틀리고 11시 29분에 16번째로 풀었습니다.<br />4번은 계절학교에서 비슷한 느낌의 문제를 풀었던 기억이 있어서 어렵지 않게 풀었습니다. 14시 01분에 11번째로 풀었습니다. 사소한 실수가 몇 가지 있어서 디버깅하는데 시간이 오래 걸렸습니다.<br />5번은 못 푸는 문제같아서 Subtask 1만 풀고 놀았습니다.</p> <p>작년보다 쉽게 느껴졌는데 만점자 수 보면 아닌 것 같기도 하고… 개인적으로 올해 3번과 4번이 작년 3번(산탄총)보다 만점자 수가 적은 게 잘 이해가 안 갑니다.</p> <h4 id="1-수열-연산">1. 수열 연산</h4> <p><code class="language-plaintext highlighter-rouge">update(1, N)</code>을 $\max(0, K-\min A)$번 호출하면 최소 횟수는 쉽게 달성할 수 있습니다. 최소 비용을 만드는 방법을 생각해 봅시다.</p> <p>$\max(0,k-\min A)$번을 유지하면서 비용을 줄이기 위해서는 <code class="language-plaintext highlighter-rouge">update(1, N)</code>에 대응되는 작업을 한 번의 쿼리로 수행해야 합니다. 즉, $K$ 미만인 수를 전부 <code class="language-plaintext highlighter-rouge">Update</code>로 처리해야 합니다. 따라서 투 포인터 느낌으로 양끝에서 $K$ 이상인 원소들을 떼어내면서 <code class="language-plaintext highlighter-rouge">update</code>를 호출하면 문제를 해결할 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="k">using</span> <span class="n">ll</span> <span class="o">=</span> <span class="kt">long</span> <span class="kt">long</span><span class="p">;</span> <span class="n">ll</span> <span class="n">N</span><span class="p">,</span> <span class="n">K</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="mi">101010</span><span class="p">],</span> <span class="n">B</span><span class="p">[</span><span class="mi">101010</span><span class="p">],</span> <span class="n">R</span><span class="p">;</span> <span class="kt">void</span> <span class="nf">Solve</span><span class="p">(){</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span> <span class="o">&gt;&gt;</span> <span class="n">K</span><span class="p">;</span> <span class="n">R</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">B</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="mi">0LL</span><span class="p">,</span> <span class="n">K</span> <span class="o">-</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span> <span class="k">if</span><span class="p">(</span><span class="o">*</span><span class="n">max_element</span><span class="p">(</span><span class="n">B</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">B</span><span class="o">+</span><span class="n">N</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">){</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="mi">0</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span> <span class="o">&lt;&lt;</span> <span class="mi">0</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="n">ll</span> <span class="n">l</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span> <span class="o">=</span> <span class="n">N</span><span class="p">,</span> <span class="n">add</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">while</span><span class="p">(</span><span class="n">l</span> <span class="o">&lt;=</span> <span class="n">r</span> <span class="o">&amp;&amp;</span> <span class="n">B</span><span class="p">[</span><span class="n">l</span><span class="p">]</span> <span class="o">-</span> <span class="n">add</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="n">l</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">while</span><span class="p">(</span><span class="n">l</span> <span class="o">&lt;=</span> <span class="n">r</span> <span class="o">&amp;&amp;</span> <span class="n">B</span><span class="p">[</span><span class="n">r</span><span class="p">]</span> <span class="o">-</span> <span class="n">add</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="n">r</span> <span class="o">-=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">while</span><span class="p">(</span><span class="n">l</span> <span class="o">&lt;=</span> <span class="n">r</span><span class="p">){</span> <span class="n">ll</span> <span class="n">now</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">B</span><span class="p">[</span><span class="n">l</span><span class="p">]</span> <span class="o">-</span> <span class="n">add</span><span class="p">,</span> <span class="n">B</span><span class="p">[</span><span class="n">r</span><span class="p">]</span> <span class="o">-</span> <span class="n">add</span><span class="p">);</span> <span class="n">add</span> <span class="o">+=</span> <span class="n">now</span><span class="p">;</span> <span class="n">R</span> <span class="o">+=</span> <span class="p">(</span><span class="n">r</span> <span class="o">-</span> <span class="n">l</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="n">now</span><span class="p">;</span> <span class="k">while</span><span class="p">(</span><span class="n">l</span> <span class="o">&lt;=</span> <span class="n">r</span> <span class="o">&amp;&amp;</span> <span class="n">B</span><span class="p">[</span><span class="n">l</span><span class="p">]</span> <span class="o">-</span> <span class="n">add</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="n">l</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">while</span><span class="p">(</span><span class="n">l</span> <span class="o">&lt;=</span> <span class="n">r</span> <span class="o">&amp;&amp;</span> <span class="n">B</span><span class="p">[</span><span class="n">r</span><span class="p">]</span> <span class="o">-</span> <span class="n">add</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="n">r</span> <span class="o">-=</span> <span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">add</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span> <span class="o">&lt;&lt;</span> <span class="n">R</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="kt">int</span> <span class="n">TC</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">TC</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">tc</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">tc</span><span class="o">&lt;=</span><span class="n">TC</span><span class="p">;</span> <span class="n">tc</span><span class="o">++</span><span class="p">){</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Case #"</span> <span class="o">&lt;&lt;</span> <span class="n">tc</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="n">Solve</span><span class="p">();</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <h4 id="2-반-협동게임">2. 반 협동게임</h4> <p>멀리 있는 학생부터 매칭하면 됩니다. 매칭의 비용은 Fenwick Tree 등을 이용해 $O(\log N)$ 시간에 계산할 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="k">using</span> <span class="n">ll</span> <span class="o">=</span> <span class="kt">long</span> <span class="kt">long</span><span class="p">;</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="mi">303030</span><span class="p">],</span> <span class="n">T</span><span class="p">[</span><span class="mi">303030</span><span class="p">];</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">G</span><span class="p">[</span><span class="mi">303030</span><span class="p">];</span> <span class="kt">void</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span> <span class="k">for</span><span class="p">(</span><span class="n">x</span><span class="o">+=</span><span class="mi">3</span><span class="p">;</span> <span class="n">x</span><span class="o">&lt;</span><span class="mi">303030</span><span class="p">;</span> <span class="n">x</span><span class="o">+=</span><span class="n">x</span><span class="o">&amp;-</span><span class="n">x</span><span class="p">)</span> <span class="n">T</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">++</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">Get</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span> <span class="kt">int</span> <span class="n">ret</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="n">x</span><span class="o">+=</span><span class="mi">3</span><span class="p">;</span> <span class="n">x</span><span class="p">;</span> <span class="n">x</span><span class="o">-=</span><span class="n">x</span><span class="o">&amp;-</span><span class="n">x</span><span class="p">)</span> <span class="n">ret</span> <span class="o">+=</span> <span class="n">T</span><span class="p">[</span><span class="n">x</span><span class="p">];</span> <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">Solve</span><span class="p">(){</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">G</span><span class="p">[</span><span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">]].</span><span class="n">push_back</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">V</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">*</span><span class="mi">2</span><span class="o">&lt;</span><span class="n">G</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">size</span><span class="p">();</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="n">V</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">G</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">],</span> <span class="n">G</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">G</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">size</span><span class="p">()</span><span class="o">-</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">]);</span> <span class="p">}</span> <span class="n">sort</span><span class="p">(</span><span class="n">V</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">V</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="p">[](</span><span class="k">auto</span> <span class="n">a</span><span class="p">,</span> <span class="k">auto</span> <span class="n">b</span><span class="p">){</span> <span class="k">return</span> <span class="n">a</span><span class="p">.</span><span class="n">second</span> <span class="o">-</span> <span class="n">a</span><span class="p">.</span><span class="n">first</span> <span class="o">&gt;</span> <span class="n">b</span><span class="p">.</span><span class="n">second</span> <span class="o">-</span> <span class="n">b</span><span class="p">.</span><span class="n">first</span><span class="p">;</span> <span class="p">});</span> <span class="n">ll</span> <span class="n">R</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="p">[</span><span class="n">s</span><span class="p">,</span><span class="n">e</span><span class="p">]</span> <span class="o">:</span> <span class="n">V</span><span class="p">){</span> <span class="n">R</span> <span class="o">+=</span> <span class="p">(</span><span class="n">e</span> <span class="o">-</span> <span class="n">Get</span><span class="p">(</span><span class="n">e</span><span class="o">-</span><span class="mi">1</span><span class="p">))</span> <span class="o">-</span> <span class="p">(</span><span class="n">s</span> <span class="o">-</span> <span class="n">Get</span><span class="p">(</span><span class="n">s</span><span class="o">-</span><span class="mi">1</span><span class="p">));</span> <span class="n">Add</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> <span class="n">Add</span><span class="p">(</span><span class="n">e</span><span class="p">);</span> <span class="p">}</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">R</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="n">memset</span><span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span> <span class="n">T</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">G</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">clear</span><span class="p">();</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="kt">int</span> <span class="n">TC</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">TC</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">tc</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">tc</span><span class="o">&lt;=</span><span class="n">TC</span><span class="p">;</span> <span class="n">tc</span><span class="o">++</span><span class="p">){</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Case #"</span> <span class="o">&lt;&lt;</span> <span class="n">tc</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="n">Solve</span><span class="p">();</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <h4 id="3-abc">3. ABC</h4> <p>$K = \infty$인 경우와 $K \neq \infty$인 경우를 나눠서 해결합니다. $K = \infty$인 경우를 먼저 보겠습니다.</p> <p>만약 어떤 SCC에 A, B, C 간선이 모두 있으면 정답은 $\infty$입니다. 그렇지 않은 경우, 각각의 SCC를 하나의 정점으로 압축한 DAG를 생각해 봅시다.<br />DAG의 각 정점을 3개의 정점으로 분할합니다. 정점 $(v, e)$는 마지막으로 $e$ 글자를 붙여서 $v$에 도달했다는 것을 의미합니다. 만약 SCC 안에 간선이 있다면 $(v,A) \rightarrow (v,B)$와 같은 간선을 적절히 추가하고, 글자를 붙이지 않는 경우는 $(v,e) \rightarrow (u,e)$ 형태의 가중치가 0인 간선을 추가하면 됩니다.<br />이렇게 만든 그래프는 DAG이므로 선형 시간에 최장 거리를 구할 수 있습니다.</p> <p>$K \neq \infty$인 경우는 조금 더 복잡합니다.<br />그래프의 각 정점을 $3K$개로 분할합니다. 정점 $(v,e,s)$는 마지막으로 $e$ 글자를 붙여서 $v$에 도달했고, 지금까지 글자를 $s$번 붙이지 않았다는 것을 의미합니다. 만약 이렇게 해서 만든 그래프에 A, B, C 간선이 모두 들어간 SCC가 존재하면 정답은 $\infty$입니다.<br />그렇지 않은 경우, 즉 각 SCC에 최대 2가지 종류의 간선만 존재하는 경우를 생각해 봅시다. 잘 생각해 보면 self loop가 존재하지 않기 때문에 그래프에 사이클이 존재하지 않는다는 것을 알 수 있습니다. DAG이므로 선형 시간에 최장 거리를 구하면 됩니다.</p> <p>$K \neq \infty$이면 $K \leq 2$이므로 $K$를 상수라고 생각하면, 두 가지 경우 모두 $O(N+M)$ 시간에 해결할 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">M</span><span class="p">,</span> <span class="n">K</span><span class="p">,</span> <span class="n">C</span><span class="p">[</span><span class="mi">909090</span><span class="p">],</span> <span class="n">D</span><span class="p">[</span><span class="mi">909090</span><span class="p">],</span> <span class="n">In</span><span class="p">[</span><span class="mi">909090</span><span class="p">];</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">tuple</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="kt">int</span><span class="p">,</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">E</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">G</span><span class="p">[</span><span class="mi">909090</span><span class="p">],</span> <span class="n">G2</span><span class="p">[</span><span class="mi">909090</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">909090</span><span class="p">],</span> <span class="n">V</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">T</span><span class="p">[</span><span class="mi">303030</span><span class="p">];</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="nf">ID</span><span class="p">(</span><span class="kt">int</span> <span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">ch</span><span class="p">,</span> <span class="kt">int</span> <span class="n">skip</span><span class="p">){</span> <span class="k">return</span> <span class="p">(</span><span class="n">v</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">9</span> <span class="o">+</span> <span class="n">ch</span> <span class="o">*</span> <span class="mi">3</span> <span class="o">+</span> <span class="n">skip</span><span class="p">;</span> <span class="p">}</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="nf">AddEdge</span><span class="p">(</span><span class="kt">int</span> <span class="n">s</span><span class="p">,</span> <span class="kt">int</span> <span class="n">e</span><span class="p">){</span> <span class="n">G</span><span class="p">[</span><span class="n">s</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">e</span><span class="p">);</span> <span class="n">G2</span><span class="p">[</span><span class="n">e</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> <span class="n">In</span><span class="p">[</span><span class="n">e</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">DFS1</span><span class="p">(</span><span class="kt">int</span> <span class="n">v</span><span class="p">){</span> <span class="n">C</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="n">i</span> <span class="o">:</span> <span class="n">G</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="n">DFS1</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> <span class="n">V</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">v</span><span class="p">);</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">DFS2</span><span class="p">(</span><span class="kt">int</span> <span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">c</span><span class="p">){</span> <span class="n">C</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">c</span><span class="p">;</span> <span class="n">S</span><span class="p">[</span><span class="n">c</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">v</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="n">i</span> <span class="o">:</span> <span class="n">G2</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="k">if</span><span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">DFS2</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">c</span><span class="p">);</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">GetSCC</span><span class="p">(</span><span class="kt">int</span> <span class="n">lo</span><span class="p">,</span> <span class="kt">int</span> <span class="n">hi</span><span class="p">){</span> <span class="kt">int</span> <span class="n">pv</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">V</span><span class="p">.</span><span class="n">clear</span><span class="p">();</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="n">lo</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">hi</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="n">DFS1</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> <span class="n">reverse</span><span class="p">(</span><span class="n">V</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">V</span><span class="p">.</span><span class="n">end</span><span class="p">());</span> <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="n">i</span> <span class="o">:</span> <span class="n">V</span><span class="p">)</span> <span class="k">if</span><span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">DFS2</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="o">++</span><span class="n">pv</span><span class="p">);</span> <span class="k">return</span> <span class="n">pv</span><span class="p">;</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">Clear</span><span class="p">(</span><span class="kt">int</span> <span class="n">lo</span><span class="p">,</span> <span class="kt">int</span> <span class="n">hi</span><span class="p">,</span> <span class="kt">int</span> <span class="n">sz</span><span class="p">){</span> <span class="n">memset</span><span class="p">(</span><span class="n">C</span><span class="o">+</span><span class="n">lo</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span><span class="o">*</span><span class="p">(</span><span class="n">hi</span><span class="o">-</span><span class="n">lo</span><span class="o">+</span><span class="mi">1</span><span class="p">));</span> <span class="n">memset</span><span class="p">(</span><span class="n">D</span><span class="o">+</span><span class="n">lo</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span><span class="o">*</span><span class="p">(</span><span class="n">hi</span><span class="o">-</span><span class="n">lo</span><span class="o">+</span><span class="mi">1</span><span class="p">));</span> <span class="n">memset</span><span class="p">(</span><span class="n">In</span><span class="o">+</span><span class="n">lo</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">In</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span><span class="o">*</span><span class="p">(</span><span class="n">hi</span><span class="o">-</span><span class="n">lo</span><span class="o">+</span><span class="mi">1</span><span class="p">));</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="n">lo</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">hi</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">G</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">clear</span><span class="p">(),</span> <span class="n">G2</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">clear</span><span class="p">();</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">sz</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">clear</span><span class="p">();</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">SolveFinite</span><span class="p">(){</span> <span class="k">for</span><span class="p">(</span><span class="k">const</span> <span class="k">auto</span> <span class="o">&amp;</span><span class="p">[</span><span class="n">s</span><span class="p">,</span><span class="n">e</span><span class="p">,</span><span class="n">c</span><span class="p">]</span> <span class="o">:</span> <span class="n">E</span><span class="p">){</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">3</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">AddEdge</span><span class="p">(</span><span class="n">ID</span><span class="p">(</span><span class="n">s</span><span class="p">,(</span><span class="n">c</span><span class="o">+</span><span class="mi">2</span><span class="p">)</span><span class="o">%</span><span class="mi">3</span><span class="p">,</span><span class="n">i</span><span class="p">),</span> <span class="n">ID</span><span class="p">(</span><span class="n">e</span><span class="p">,</span><span class="n">c</span><span class="p">,</span><span class="n">i</span><span class="p">));</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">3</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="mi">2</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="n">AddEdge</span><span class="p">(</span><span class="n">ID</span><span class="p">(</span><span class="n">s</span><span class="p">,</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">),</span> <span class="n">ID</span><span class="p">(</span><span class="n">e</span><span class="p">,</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="o">+</span><span class="mi">1</span><span class="p">));</span> <span class="p">}</span> <span class="kt">int</span> <span class="n">lo</span> <span class="o">=</span> <span class="n">ID</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">),</span> <span class="n">hi</span> <span class="o">=</span> <span class="n">ID</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">sz</span> <span class="o">=</span> <span class="n">GetSCC</span><span class="p">(</span><span class="n">lo</span><span class="p">,</span> <span class="n">hi</span><span class="p">),</span> <span class="n">res</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">sz</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="k">if</span><span class="p">(</span><span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">size</span><span class="p">()</span> <span class="o">&gt;=</span> <span class="mi">3</span><span class="p">)</span> <span class="p">{</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="o">-</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span> <span class="n">Clear</span><span class="p">(</span><span class="n">lo</span><span class="p">,</span> <span class="n">hi</span><span class="p">,</span> <span class="n">sz</span><span class="p">);</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="n">queue</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">Q</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="n">lo</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">hi</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="k">if</span><span class="p">(</span><span class="n">In</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="n">Q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> <span class="k">while</span><span class="p">(</span><span class="o">!</span><span class="n">Q</span><span class="p">.</span><span class="n">empty</span><span class="p">()){</span> <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">Q</span><span class="p">.</span><span class="n">front</span><span class="p">();</span> <span class="n">Q</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span> <span class="k">if</span><span class="p">(</span><span class="n">v</span> <span class="o">%</span> <span class="mi">3</span> <span class="o">&lt;=</span> <span class="n">K</span><span class="p">)</span> <span class="n">res</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">-</span> <span class="n">v</span> <span class="o">%</span> <span class="mi">3</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="n">i</span> <span class="o">:</span> <span class="n">G</span><span class="p">[</span><span class="n">v</span><span class="p">]){</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">D</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="o">!--</span><span class="n">In</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="n">Q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">res</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span> <span class="n">Clear</span><span class="p">(</span><span class="n">lo</span><span class="p">,</span> <span class="n">hi</span><span class="p">,</span> <span class="n">sz</span><span class="p">);</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">SolveInfinite</span><span class="p">(){</span> <span class="k">for</span><span class="p">(</span><span class="k">const</span> <span class="k">auto</span> <span class="o">&amp;</span><span class="p">[</span><span class="n">s</span><span class="p">,</span><span class="n">e</span><span class="p">,</span><span class="n">c</span><span class="p">]</span> <span class="o">:</span> <span class="n">E</span><span class="p">)</span> <span class="n">AddEdge</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">e</span><span class="p">);</span> <span class="kt">int</span> <span class="n">lo</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">hi</span> <span class="o">=</span> <span class="n">N</span><span class="p">,</span> <span class="n">sz</span> <span class="o">=</span> <span class="n">GetSCC</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">N</span><span class="p">),</span> <span class="n">res</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">deg</span><span class="p">(</span><span class="n">sz</span><span class="o">*</span><span class="mi">3</span><span class="o">+</span><span class="mi">10</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="k">auto</span> <span class="n">id</span> <span class="o">=</span> <span class="p">[</span><span class="o">&amp;</span><span class="p">](</span><span class="kt">int</span> <span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">c</span><span class="p">){</span> <span class="k">return</span> <span class="p">(</span><span class="n">v</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">3</span> <span class="o">+</span> <span class="n">c</span><span class="p">;</span> <span class="p">};</span> <span class="k">auto</span> <span class="n">add_edge</span> <span class="o">=</span> <span class="p">[</span><span class="o">&amp;</span><span class="p">](</span><span class="kt">int</span> <span class="n">s</span><span class="p">,</span> <span class="kt">int</span> <span class="n">e</span><span class="p">,</span> <span class="kt">int</span> <span class="n">w</span><span class="p">){</span> <span class="n">T</span><span class="p">[</span><span class="n">s</span><span class="p">].</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">w</span><span class="p">);</span> <span class="n">deg</span><span class="p">[</span><span class="n">e</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span> <span class="p">};</span> <span class="k">for</span><span class="p">(</span><span class="k">const</span> <span class="k">auto</span> <span class="o">&amp;</span><span class="p">[</span><span class="n">s</span><span class="p">,</span><span class="n">e</span><span class="p">,</span><span class="n">c</span><span class="p">]</span> <span class="o">:</span> <span class="n">E</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">==</span> <span class="n">C</span><span class="p">[</span><span class="n">e</span><span class="p">])</span> <span class="n">add_edge</span><span class="p">(</span><span class="n">id</span><span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="n">s</span><span class="p">],(</span><span class="n">c</span><span class="o">+</span><span class="mi">2</span><span class="p">)</span><span class="o">%</span><span class="mi">3</span><span class="p">),</span> <span class="n">id</span><span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="n">s</span><span class="p">],</span><span class="n">c</span><span class="p">),</span> <span class="mi">1</span><span class="p">);</span> <span class="k">else</span><span class="p">{</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">3</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">add_edge</span><span class="p">(</span><span class="n">id</span><span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="n">s</span><span class="p">],</span><span class="n">i</span><span class="p">),</span> <span class="n">id</span><span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="n">e</span><span class="p">],</span><span class="n">i</span><span class="p">),</span> <span class="mi">0</span><span class="p">);</span> <span class="n">add_edge</span><span class="p">(</span><span class="n">id</span><span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="n">s</span><span class="p">],(</span><span class="n">c</span><span class="o">+</span><span class="mi">2</span><span class="p">)</span><span class="o">%</span><span class="mi">3</span><span class="p">),</span> <span class="n">id</span><span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="n">e</span><span class="p">],</span><span class="n">c</span><span class="p">),</span> <span class="mi">1</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="n">queue</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">Q</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="n">id</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">id</span><span class="p">(</span><span class="n">sz</span><span class="p">,</span><span class="mi">2</span><span class="p">);</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">deg</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="n">Q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> <span class="k">while</span><span class="p">(</span><span class="o">!</span><span class="n">Q</span><span class="p">.</span><span class="n">empty</span><span class="p">()){</span> <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">Q</span><span class="p">.</span><span class="n">front</span><span class="p">();</span> <span class="n">Q</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span> <span class="n">res</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">v</span><span class="p">]);</span> <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="p">[</span><span class="n">i</span><span class="p">,</span><span class="n">w</span><span class="p">]</span> <span class="o">:</span> <span class="n">T</span><span class="p">[</span><span class="n">v</span><span class="p">]){</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">D</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="o">!--</span><span class="n">deg</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="n">Q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="o">*</span><span class="n">max_element</span><span class="p">(</span><span class="n">deg</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">deg</span><span class="p">.</span><span class="n">end</span><span class="p">())</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="o">-</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span> <span class="k">else</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">res</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span> <span class="n">Clear</span><span class="p">(</span><span class="n">lo</span><span class="p">,</span> <span class="n">hi</span><span class="p">,</span> <span class="n">sz</span><span class="p">);</span> <span class="n">lo</span> <span class="o">=</span> <span class="n">id</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="n">hi</span> <span class="o">=</span> <span class="n">id</span><span class="p">(</span><span class="n">sz</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span> <span class="n">memset</span><span class="p">(</span><span class="n">D</span><span class="o">+</span><span class="n">lo</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span><span class="o">*</span><span class="p">(</span><span class="n">hi</span><span class="o">-</span><span class="n">lo</span><span class="o">+</span><span class="mi">1</span><span class="p">));</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="n">lo</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">hi</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">T</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">clear</span><span class="p">();</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">Solve</span><span class="p">(){</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span> <span class="o">&gt;&gt;</span> <span class="n">M</span> <span class="o">&gt;&gt;</span> <span class="n">K</span><span class="p">;</span> <span class="n">E</span><span class="p">.</span><span class="n">reserve</span><span class="p">(</span><span class="n">M</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">M</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="kt">int</span> <span class="n">s</span><span class="p">,</span> <span class="n">e</span><span class="p">;</span> <span class="kt">char</span> <span class="n">c</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">s</span> <span class="o">&gt;&gt;</span> <span class="n">e</span> <span class="o">&gt;&gt;</span> <span class="n">c</span><span class="p">;</span> <span class="n">E</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">e</span><span class="p">,</span> <span class="n">c</span><span class="o">-</span><span class="sc">'A'</span><span class="p">);</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">K</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">SolveFinite</span><span class="p">();</span> <span class="k">else</span> <span class="n">SolveInfinite</span><span class="p">();</span> <span class="n">E</span><span class="p">.</span><span class="n">clear</span><span class="p">();</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="kt">int</span> <span class="n">TC</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">TC</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">tc</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">tc</span><span class="o">&lt;=</span><span class="n">TC</span><span class="p">;</span> <span class="n">tc</span><span class="o">++</span><span class="p">){</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Case #"</span> <span class="o">&lt;&lt;</span> <span class="n">tc</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="n">Solve</span><span class="p">();</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <h4 id="4-직사각형">4. 직사각형</h4> <p>보통 이런 문제는 $r_1, r_2$를 $O(N^2)$에 고정하고, 적당한 방법을 통해 $c_1, c_2$를 잘 계산하는 방식으로 해결할 수 있습니다. 하지만 이 문제는 이런 방식으로 접근했을 때 $O(N^4)$ 미만으로 푸는 방법이 안 보여서 다른 방식으로 접근했습니다.</p> <p>직사각형에 포함되는 수의 최솟값 $i$를 고정합시다. $i$만 포함된 직사각형에서 시작해서, 수를 하나씩 추가하면서 직사각형을 확장하는 방식으로 진행할 것입니다.<br />직사각형의 크기는 $1\times 1$부터 시작해서 최대 $N\times N$까지 확장되므로, 고정된 $i$에 대해 직사각형의 확장은 $O(N)$번 발생합니다. 따라서 전체 확장 횟수는 $O(N^3)$으로 문제를 해결하기에 충분합니다. 직사각형이 확장되는 타이밍과 직사각형의 최솟값/최댓값의 변화를 빠르게 계산하는 방법을 알아봅시다.</p> <p>만약 현재 직사각형이 꽉찬 직사각형인 경우 (최댓값 + 1)을 추가하고, 그렇지 않은 경우에는 마지막으로 추가한 수부터 현재 직사각형 영역의 최댓값까지의 수를 전부 추가합니다.<br />한 번에 수를 여러 개 추가할 때 직사각형 크기의 변화는, 추가하는 수가 연속적이라는 것을 이용해 RMQ를 날리면 됩니다. Sparse Table을 이용해 $O(N^2 \log N^2)$ 전처리를 하면 $O(1)$에 RMQ를 할 수 있습니다.<br />최솟값과 최댓값의 변화를 관리하는 것은, 매번 한 줄씩 확장된다는 점을 이용해 각 행과 열에 RMQ를 날리면 됩니다. Sparse Table을 $2N$개 관리하면 RMQ를 $O(1)$에 처리할 수 있습니다.</p> <p>직사각형을 한 번 확장하는데 $O(1)$이 걸리므로 전체 문제를 $O(N^3)$에 해결할 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="c1">// range minimum query</span> <span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="nc">T</span><span class="p">,</span> <span class="k">class</span> <span class="nc">O</span><span class="p">&gt;</span> <span class="k">struct</span> <span class="nc">SparseTable</span> <span class="p">{</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;&gt;</span> <span class="n">a</span><span class="p">;</span> <span class="kt">void</span> <span class="n">resize</span><span class="p">(</span><span class="kt">int</span> <span class="n">sz</span><span class="p">){</span> <span class="kt">int</span> <span class="n">lg</span> <span class="o">=</span> <span class="n">__lg</span><span class="p">(</span><span class="n">sz</span><span class="p">);</span> <span class="n">a</span> <span class="o">=</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;&gt;</span><span class="p">(</span><span class="n">lg</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="n">sz</span><span class="p">));</span> <span class="p">}</span> <span class="kt">void</span> <span class="n">set</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="n">T</span> <span class="n">v</span><span class="p">){</span> <span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span><span class="p">;</span> <span class="p">}</span> <span class="kt">void</span> <span class="n">build</span><span class="p">(){</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">a</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">size</span><span class="p">();</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="k">if</span><span class="p">(</span><span class="n">j</span><span class="o">+</span><span class="p">(</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="p">(</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">))</span> <span class="o">&lt;</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">size</span><span class="p">())</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">],</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="o">+</span><span class="p">(</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="p">(</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">))],</span> <span class="n">O</span><span class="p">());</span> <span class="p">}</span> <span class="n">T</span> <span class="n">get</span><span class="p">(</span><span class="kt">int</span> <span class="n">s</span><span class="p">,</span> <span class="kt">int</span> <span class="n">e</span><span class="p">){</span> <span class="kt">int</span> <span class="n">k</span> <span class="o">=</span> <span class="n">__lg</span><span class="p">(</span><span class="n">e</span><span class="o">-</span><span class="n">s</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span> <span class="k">return</span> <span class="n">min</span><span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="n">s</span><span class="p">],</span> <span class="n">a</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="n">e</span><span class="o">-</span><span class="p">(</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="n">k</span><span class="p">)</span><span class="o">+</span><span class="mi">1</span><span class="p">],</span> <span class="n">O</span><span class="p">());</span> <span class="p">}</span> <span class="p">};</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">S</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="mi">256</span><span class="p">][</span><span class="mi">256</span><span class="p">],</span> <span class="n">R</span><span class="p">[</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="mi">16</span><span class="p">],</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="mi">16</span><span class="p">];</span> <span class="n">SparseTable</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">less</span><span class="o">&lt;&gt;&gt;</span> <span class="n">MinR</span><span class="p">[</span><span class="mi">257</span><span class="p">],</span> <span class="n">MinC</span><span class="p">[</span><span class="mi">257</span><span class="p">];</span> <span class="n">SparseTable</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">greater</span><span class="o">&lt;&gt;&gt;</span> <span class="n">MaxR</span><span class="p">[</span><span class="mi">257</span><span class="p">],</span> <span class="n">MaxC</span><span class="p">[</span><span class="mi">257</span><span class="p">];</span> <span class="kt">void</span> <span class="nf">Solve</span><span class="p">(){</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span><span class="p">;</span> <span class="n">S</span> <span class="o">=</span> <span class="n">N</span> <span class="o">*</span> <span class="n">N</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">-=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="n">R</span><span class="p">[</span><span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]]</span> <span class="o">=</span> <span class="n">i</span><span class="p">,</span> <span class="n">C</span><span class="p">[</span><span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]]</span> <span class="o">=</span> <span class="n">j</span><span class="p">;</span> <span class="n">MinR</span><span class="p">[</span><span class="n">N</span><span class="p">].</span><span class="n">resize</span><span class="p">(</span><span class="n">S</span><span class="p">);</span> <span class="n">MaxR</span><span class="p">[</span><span class="n">N</span><span class="p">].</span><span class="n">resize</span><span class="p">(</span><span class="n">S</span><span class="p">);</span> <span class="n">MinC</span><span class="p">[</span><span class="n">N</span><span class="p">].</span><span class="n">resize</span><span class="p">(</span><span class="n">S</span><span class="p">);</span> <span class="n">MaxC</span><span class="p">[</span><span class="n">N</span><span class="p">].</span><span class="n">resize</span><span class="p">(</span><span class="n">S</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">S</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">MinR</span><span class="p">[</span><span class="n">N</span><span class="p">].</span><span class="n">set</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">R</span><span class="p">[</span><span class="n">i</span><span class="p">]),</span> <span class="n">MaxR</span><span class="p">[</span><span class="n">N</span><span class="p">].</span><span class="n">set</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">R</span><span class="p">[</span><span class="n">i</span><span class="p">]),</span> <span class="n">MinC</span><span class="p">[</span><span class="n">N</span><span class="p">].</span><span class="n">set</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">]),</span> <span class="n">MaxC</span><span class="p">[</span><span class="n">N</span><span class="p">].</span><span class="n">set</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">MinR</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">resize</span><span class="p">(</span><span class="n">N</span><span class="p">),</span> <span class="n">MaxR</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">resize</span><span class="p">(</span><span class="n">N</span><span class="p">),</span> <span class="n">MinC</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">resize</span><span class="p">(</span><span class="n">N</span><span class="p">),</span> <span class="n">MaxC</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">resize</span><span class="p">(</span><span class="n">N</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="n">MinR</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">set</span><span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]),</span> <span class="n">MinC</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">set</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="n">MaxR</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">set</span><span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]),</span> <span class="n">MaxC</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">set</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">MinR</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">build</span><span class="p">(),</span> <span class="n">MaxR</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">build</span><span class="p">(),</span> <span class="n">MinC</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">build</span><span class="p">(),</span> <span class="n">MaxC</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">build</span><span class="p">();</span> <span class="kt">int</span> <span class="n">res</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">S</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="kt">int</span> <span class="n">r1</span> <span class="o">=</span> <span class="n">R</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">r2</span> <span class="o">=</span> <span class="n">R</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">c1</span> <span class="o">=</span> <span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">c2</span> <span class="o">=</span> <span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">mn</span> <span class="o">=</span> <span class="n">i</span><span class="p">,</span> <span class="n">mx</span> <span class="o">=</span> <span class="n">i</span><span class="p">,</span> <span class="n">lst</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span> <span class="k">while</span><span class="p">(</span><span class="nb">true</span><span class="p">){</span> <span class="kt">int</span> <span class="n">sz</span> <span class="o">=</span> <span class="p">(</span><span class="n">r2</span> <span class="o">-</span> <span class="n">r1</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="n">c2</span> <span class="o">-</span> <span class="n">c1</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="n">mn</span> <span class="o">&lt;</span> <span class="n">i</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">lst</span> <span class="o">==</span> <span class="n">mx</span> <span class="o">&amp;&amp;</span> <span class="n">sz</span> <span class="o">==</span> <span class="n">mx</span> <span class="o">-</span> <span class="n">mn</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="n">res</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">lst</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">==</span> <span class="n">S</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span> <span class="n">lst</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">lst</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">mx</span><span class="p">);</span> <span class="kt">int</span> <span class="n">r_mn</span> <span class="o">=</span> <span class="n">MinR</span><span class="p">[</span><span class="n">N</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="n">mn</span><span class="p">,</span> <span class="n">lst</span><span class="p">),</span> <span class="n">r_mx</span> <span class="o">=</span> <span class="n">MaxR</span><span class="p">[</span><span class="n">N</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="n">mn</span><span class="p">,</span> <span class="n">lst</span><span class="p">);</span> <span class="kt">int</span> <span class="n">c_mn</span> <span class="o">=</span> <span class="n">MinC</span><span class="p">[</span><span class="n">N</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="n">mn</span><span class="p">,</span> <span class="n">lst</span><span class="p">),</span> <span class="n">c_mx</span> <span class="o">=</span> <span class="n">MaxC</span><span class="p">[</span><span class="n">N</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="n">mn</span><span class="p">,</span> <span class="n">lst</span><span class="p">);</span> <span class="k">while</span><span class="p">(</span><span class="n">r_mn</span> <span class="o">&lt;</span> <span class="n">r1</span><span class="p">)</span> <span class="n">r1</span><span class="o">--</span><span class="p">,</span> <span class="n">mn</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">mn</span><span class="p">,</span> <span class="n">MinR</span><span class="p">[</span><span class="n">r1</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="n">c1</span><span class="p">,</span> <span class="n">c2</span><span class="p">)),</span> <span class="n">mx</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">mx</span><span class="p">,</span> <span class="n">MaxR</span><span class="p">[</span><span class="n">r1</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="n">c1</span><span class="p">,</span> <span class="n">c2</span><span class="p">));</span> <span class="k">while</span><span class="p">(</span><span class="n">r_mx</span> <span class="o">&gt;</span> <span class="n">r2</span><span class="p">)</span> <span class="n">r2</span><span class="o">++</span><span class="p">,</span> <span class="n">mn</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">mn</span><span class="p">,</span> <span class="n">MinR</span><span class="p">[</span><span class="n">r2</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="n">c1</span><span class="p">,</span> <span class="n">c2</span><span class="p">)),</span> <span class="n">mx</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">mx</span><span class="p">,</span> <span class="n">MaxR</span><span class="p">[</span><span class="n">r2</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="n">c1</span><span class="p">,</span> <span class="n">c2</span><span class="p">));</span> <span class="k">while</span><span class="p">(</span><span class="n">c_mn</span> <span class="o">&lt;</span> <span class="n">c1</span><span class="p">)</span> <span class="n">c1</span><span class="o">--</span><span class="p">,</span> <span class="n">mn</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">mn</span><span class="p">,</span> <span class="n">MinC</span><span class="p">[</span><span class="n">c1</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="n">r1</span><span class="p">,</span> <span class="n">r2</span><span class="p">)),</span> <span class="n">mx</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">mx</span><span class="p">,</span> <span class="n">MaxC</span><span class="p">[</span><span class="n">c1</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="n">r1</span><span class="p">,</span> <span class="n">r2</span><span class="p">));</span> <span class="k">while</span><span class="p">(</span><span class="n">c_mx</span> <span class="o">&gt;</span> <span class="n">c2</span><span class="p">)</span> <span class="n">c2</span><span class="o">++</span><span class="p">,</span> <span class="n">mn</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">mn</span><span class="p">,</span> <span class="n">MinC</span><span class="p">[</span><span class="n">c2</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="n">r1</span><span class="p">,</span> <span class="n">r2</span><span class="p">)),</span> <span class="n">mx</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">mx</span><span class="p">,</span> <span class="n">MaxC</span><span class="p">[</span><span class="n">c2</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="n">r1</span><span class="p">,</span> <span class="n">r2</span><span class="p">));</span> <span class="p">}</span> <span class="p">}</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">res</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="kt">int</span> <span class="n">TC</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">TC</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">tc</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">tc</span><span class="o">&lt;=</span><span class="n">TC</span><span class="p">;</span> <span class="n">tc</span><span class="o">++</span><span class="p">){</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Case #"</span> <span class="o">&lt;&lt;</span> <span class="n">tc</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="n">Solve</span><span class="p">();</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <h4 id="5-황금-카드">5. 황금 카드</h4> <p>Subtask 1(73점)은 Bit DP를 이용해 $O(KN2^N)$에 해결할 수 있습니다. Subtask 2부터는 모릅니다.<br />아래 코드는 Subtask 1 코드입니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="k">using</span> <span class="n">ll</span> <span class="o">=</span> <span class="kt">long</span> <span class="kt">long</span><span class="p">;</span> <span class="k">constexpr</span> <span class="n">ll</span> <span class="n">MOD</span> <span class="o">=</span> <span class="mi">998244353</span><span class="p">;</span> <span class="n">ll</span> <span class="nf">Pow</span><span class="p">(</span><span class="n">ll</span> <span class="n">a</span><span class="p">,</span> <span class="n">ll</span> <span class="n">b</span><span class="p">){</span> <span class="n">ll</span> <span class="n">res</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">for</span><span class="p">(;</span> <span class="n">b</span><span class="p">;</span> <span class="n">b</span> <span class="o">&gt;&gt;=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">a</span> <span class="o">=</span> <span class="n">a</span> <span class="o">*</span> <span class="n">a</span> <span class="o">%</span> <span class="n">MOD</span><span class="p">)</span> <span class="k">if</span><span class="p">(</span><span class="n">b</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="n">res</span> <span class="o">=</span> <span class="n">res</span> <span class="o">*</span> <span class="n">a</span> <span class="o">%</span> <span class="n">MOD</span><span class="p">;</span> <span class="k">return</span> <span class="n">res</span><span class="p">;</span> <span class="p">}</span> <span class="n">ll</span> <span class="n">N</span><span class="p">,</span> <span class="n">K</span><span class="p">,</span> <span class="n">P</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="mi">50505</span><span class="p">],</span> <span class="n">D</span><span class="p">[</span><span class="mi">55</span><span class="p">][</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="mi">10</span><span class="p">],</span> <span class="n">R</span><span class="p">[</span><span class="mi">55</span><span class="p">];</span> <span class="kt">void</span> <span class="nf">Solve</span><span class="p">(){</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span> <span class="o">&gt;&gt;</span> <span class="n">K</span><span class="p">;</span> <span class="n">P</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">P</span> <span class="o">+=</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="k">if</span><span class="p">(</span><span class="n">N</span> <span class="o">&gt;</span> <span class="mi">10</span> <span class="o">||</span> <span class="n">K</span> <span class="o">&gt;</span> <span class="mi">50</span><span class="p">){</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="mi">0</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="n">memset</span><span class="p">(</span><span class="n">D</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span> <span class="n">D</span><span class="p">);</span> <span class="n">D</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">K</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="p">(</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="n">N</span><span class="p">);</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">k</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">k</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">k</span><span class="o">++</span><span class="p">){</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="o">|</span><span class="p">(</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="n">k</span><span class="p">)]</span> <span class="o">+=</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">*</span> <span class="n">A</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">%</span> <span class="n">MOD</span> <span class="o">*</span> <span class="n">Pow</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">MOD</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span> <span class="o">%</span> <span class="n">MOD</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="n">memset</span><span class="p">(</span><span class="n">R</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span> <span class="n">R</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">K</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="p">(</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="n">N</span><span class="p">);</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="n">R</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">R</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">__builtin_popcount</span><span class="p">(</span><span class="n">j</span><span class="p">)</span> <span class="o">*</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">])</span> <span class="o">%</span> <span class="n">MOD</span><span class="p">;</span> <span class="p">}</span> <span class="n">R</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">R</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">Pow</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> <span class="o">%</span> <span class="n">MOD</span><span class="p">;</span> <span class="p">}</span> <span class="n">ll</span> <span class="n">res</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">K</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">res</span> <span class="o">^=</span> <span class="n">R</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">res</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="kt">int</span> <span class="n">TC</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">TC</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">tc</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">tc</span><span class="o">&lt;=</span><span class="n">TC</span><span class="p">;</span> <span class="n">tc</span><span class="o">++</span><span class="p">){</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Case #"</span> <span class="o">&lt;&lt;</span> <span class="n">tc</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="n">Solve</span><span class="p">();</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div>JusticeHui서론제6회 천하제일 코딩대회 출제 이야기2022-07-08T00:00:00+00:002022-07-08T00:00:00+00:00https://justicehui.github.io/review/2022/07/08/sunrin-icpc-2022<h3 id="서론">서론</h3> <p>지난 2년간 온라인으로 진행되었던 천하제일 코딩대회가 3년 만에 오프라인으로 돌아왔습니다. 코로나로 인해 멈춰있던 학교 행사의 시작을 함께 하게 되어서 영광이었습니다.<br /><a href="/review/2021/08/21/sunrin-icpc-2021/">작년</a>에는 단순히 문제만 만들면 됐지만 올해는 오프라인 대회이기 때문에 문제지, 풍선, 자리 배치 등 신경 써야 할 요소가 많았습니다. 그럼에도 불구하고 잘 따라와 준 다른 출제진, 현장에서 열심히 힘을 써준 후배님들과 학교 선생님들께 이 자리를 빌려 감사하다는 말씀 전하고 싶습니다.</p> <p>저는 예선 5문제 중 1문제, 본선 10문제 중 3문제를 출제했습니다. 그 외에도 여러 잡다한 일을 했는데 이 글을 통해 하나씩 풀어보려 합니다.</p> <h3 id="대회-준비">대회 준비</h3> <p>고등학생 때 가장 즐겁게 참여했던 대회인 만큼, 이번에 참가하는 학생들도 재밌게 대회를 치를 수 있는 환경을 조성하는데 많은 노력을 기울였습니다.</p> <p>작년과 마찬가지로 어려운 사전 지식을 요구하는 문제는 최대한 배제하고, <strong>알고리즘을 공부하지 않았더라도 모두가 재미있게 풀 수 있는 문제</strong>를 목표로 출제했습니다. 오랜만에 오프라인 대회로 열리는 만큼, 많은 학생들이 즐거운 경험을 하고 그 경험을 바탕으로 문제 풀이에 흥미를 가졌으면 하는 작은 바람이 있었습니다.</p> <p>개발을 주로 공부하는 학생들은 C++에 익숙하지 않기 때문에 C++, JAVA, Python, Javascript로 모든 문제를 해결할 수 있음을 보장했습니다. 4가지 언어로 코딩해야 돼서 해야 할 일이 4배가 되었지만… 대회가 잘 마무리되었으니 저는 만족합니다. 4가지 언어로 작성된 정답 코드는 <a href="https://github.com/justiceHui/Sunrin-Contest/tree/main/Sunrin-ICPC-2022">여기</a>에서 볼 수 있습니다.</p> <p>천하제일 코딩대회는 ICPC처럼 3명이 한 대의 컴퓨터만 사용하는 대회이기 때문에 문제지를 따로 출력해서 배부해야 합니다. 3년 전에는 단순히 BOJ 화면을 출력했지만, 올해는 조금 더 높은 퀄리티의 문제지를 만들고 싶었습니다. 그래서 $\LaTeX$로 문제지를 직접 조판했습니다. 원래는 문제지 표지 디자인 외주를 맡기고 싶었지만 너무 늦게 알아보기 시작해서 맡기지 못했습니다. 문제지는 <a href="https://github.com/justiceHui/Sunrin-Contest/blob/main/Sunrin-ICPC-2022/statement.pdf">여기</a>에서 볼 수 있습니다.</p> <p>문제 해설을 위한 풀이 슬라이드도 만들어야 합니다. 풀이 슬라이드는 작년과 마찬가지로 <a href="https://github.com/ucpcc/ucpc2020-solutions-theme">UCPC 2020 beamer 테마</a>를 사용했습니다. 출제자들이 문제 풀이를 미리 요약해 준 덕분에 편하게 제작할 수 있었습니다. 풀이 슬라이드는 <a href="https://github.com/justiceHui/Sunrin-Contest/blob/main/Sunrin-ICPC-2022/editorial.pdf">여기</a>에서 볼 수 있습니다.</p> <h3 id="예선">예선</h3> <p>예선 문제는 작년과 비슷한 난이도로 출제했고, 난이도 순으로 정렬해서 참가자에게 제공했습니다. 5문제가 출제되었으며, 저는 1문제를 출제하고 모든 문제를 세팅(지문 작성, 데이터 제작 등)했습니다. 다른 출제진들은 모두 후배라서 일을 떠넘길까 고민했지만(…) 그냥 제가 하는 게 빠를 것 같아서 제가 전부 했습니다.</p> <p>작년 예선은 30분 만에 5문제를 모두 만들었는데 벌써 에이징 커브가 왔는지 올해는 문제 아이디어가 잘 나오지 않았습니다. 작년보다 더 열심히 고민했는데 더 재미없는 문제가 나와서 슬펐습니다.</p> <h3 id="예선-a---심준의-병역판정검사">예선 A - 심준의 병역판정검사</h3> <p>처음에는 누가 키(key 말고 height) 갖고 뭔가 하는 문제를 가져왔습니다. 너무 재미없어서 폐기할까 고민했는데 wesley2003이 병역판정검사 스토리를 붙여서 문제를 살려냈습니다. 원래 입력 범위는 최대 1000이었는데 float로 bmi를 계산하면 실수 오차가 발생해서 200으로 줄였습니다. 입력 범위가 작아진 덕분에 채점 데이터에 가능한 모든 데이터를 넣을 수 있었습니다.</p> <p><code class="language-plaintext highlighter-rouge">w/(h/100)/(h/100), w/h/h*100*100, w*10000/h/h, w/(h/100*h/100), w/(h*h)*100*100, w*10000/(h*h)</code> 등 창의력을 발휘해서 참가자들이 시도할 것 같은 모든 방법을 이용해 float 범위에서 통과하는 것을 확인했는데, 대회 중에 한 참가자가 double로 틀려서 당황스러웠습니다…</p> <h3 id="예선-b---11월-11일">예선 B - 11월 11일</h3> <p>저는 $m$일 전을 naive하게 계산했는데 출제자가 더 똑똑한 방법을 알려줬습니다. Python의 datetime 패키지, Javascript의 Date 객체를 이용해서 해결할 수도 있습니다. 이 문제도 입력의 범위가 작기 때문에 가능한 2100×12개의 데이터를 모두 넣었습니다.</p> <p>예제를 친절하게 주기 위해서 노력했습니다. 400의 배수라서 윤년인 해(2000년), 400의 배수가 아니지만 윤년인 해(2012년), 100의 배수라서 윤년이 아닌 해(2100년), 그냥 윤년이 아닌 해(2022년)을 모두 예제에 넣었습니다. 그래도 정답률이 낮은 거 보면 예제를 더 넣었어야 했나… 잘 모르겠습니다.</p> <h3 id="예선-c---순열-정렬">예선 C - 순열 정렬</h3> <p>그리디 하게 하면 쉽게 해결할 수 있는데 DP로 푼 학생이 많아서 놀랐습니다. 데이터를 만드는 게 조금 귀찮았는데, 일단 길이가 7 이하인 모든 순열을 다 넣고 항상 YES인 순열도 몇 개 넣었습니다. 나머지는 랜덤으로…</p> <p>원래 입력 제한이 50만이었는데 Python이랑 Javascript가 입력도 못 받고 죽어서 5만으로 줄였습니다. 사실 5만으로 줄이는 것만으로는 안 되길래 시간제한도 3초로 늘렸습니다. 어휴…</p> <h3 id="예선-d---영어-시험">예선 D - 영어 시험</h3> <p>De Bruijn Sequence를 공부하다가 substring 대신 subsequence 조건을 넣으면 쉬운 것 같아서 만든 문제입니다. 데이터 만드는 것도 쉽고 스페셜 저지 작성도 쉽고 풀이 작성도 쉬운 꿀문제입니다. 대회 끝나고 여러 사람들이 재미있다고 해줘서 기뻤습니다.</p> <h3 id="예선-e---가장-긴-등차-부분-수열">예선 E - 가장 긴 등차 부분 수열</h3> <p>여러 가지 풀이가 있고, 출제 과정에서는 $O(NX \log X)$, $O(NX)$ 풀이가 나왔습니다. 두 풀이 모두 좋은 풀이 같아서 둘 다 통과할 수 있도록 데이터를 만들었습니다. 덕분에 4가지 언어로 $O(NX), O(NX\log X), O(N^2)$ 풀이를 작성하는 개고생을 했습니다. 대회 중에는 $O(X^3), O(X^2 \log X)$ 같은 풀이도 나왔습니다.</p> <h3 id="본선">본선</h3> <p>예선 결과가 생각보다 좋지 않아서 작년보다 더 쉽게 출제했습니다. 다만 작년처럼 대놓고 쉬운 문제가 없어서 상위권을 제외한 팀들이 초반에 헤맨 것 같습니다.</p> <p>1등팀이 2시간 만에 다 풀고 자는 건 막고 싶어서 의도적으로 코딩이 귀찮은 문제도 몇 개 넣었습니다. 상위권이 다 풀고 자는 거 막겠다고 어려운 문제로 도배하면 다른 팀들이 고생하기 때문에, 귀찮은 문제와 어려운 문제 각각 한 두 문제씩 넣는 걸로 만족했습니다.</p> <p>저는 10문제 중 3문제(DGI)를 출제했고, 5문제(DGHIJ)를 세팅했습니다. 작년에는 미리 쌓아놓은 문제가 많아서 여유롭게 작업했는데, 올해는 이미 1학기에 20문제 가까이 출제해서 아이디어가 바닥났습니다. 급하게 출제하느라 별로 재미있는 문제를 만들지 못해 아쉬웠습니다.</p> <h3 id="본선-a---gravity-hackenbush">본선 A - Gravity Hackenbush</h3> <p>hackenbush 게임에 중력을 추가한 게임입니다. 무서워 보이지만 문제를 천천히 읽으면 쉽게 풀 수 있는 문제고, 실제로 많은 팀이 풀었습니다. 원래 입력 제한이 200만이었는데 Python과 Javascript가 입력받다가 죽어서…</p> <p>나정휘(jhnah917)와 난정휘(jhnan917)가 게임하는 문제였는데, 대회장에서 참가자들이 제 이름을 외치며 괴로워하는 것을 보니 기분이 이상했습니다.</p> <h3 id="본선-b---k-균형-잡힌-수">본선 B - K-균형 잡힌 수</h3> <p>가장 어려운 문제를 의도하고 만든 문제입니다. 올솔브를 지연시킬 목적으로 만들었는데 목적을 잘 달성한 것 같습니다.</p> <h3 id="본선-c---merge-the-tree-and-sequence">본선 C - Merge the Tree and Sequence</h3> <p>원래 <a href="https://www.acmicpc.net/problem/24914">Split the SSHS</a> 문제와 <a href="https://www.acmicpc.net/problem/24940">Split the GSHS</a>의 후속작인 Merge the SSHS and GSHS라는 이름으로 출제될 예정이었지만, 교내 대회 참가자들은 저 스토리를 모르기 때문에 눈물을 머금고 제목을 교체했습니다. 검수하면서 제가 가장 재밌게 푼 문제입니다.</p> <h3 id="본선-d---바지-구매">본선 D - 바지 구매</h3> <p>가장 쉬운 문제를 의도하고 만든 문제입니다. 원래는 문제가 조금 달랐었는데, 가장 쉬운 문제 치고는 너무 어려운 것 같아서 3~4번 정도 너프시켰습니다.</p> <h3 id="본선-e---반전-수와-쿼리">본선 E - 반전 수와 쿼리</h3> <p>크기가 $N$인 배열을 만들지 않고 해결할 수 있음을 알려주기 위해 $N$의 범위를 $10^9$로 줬는데, PS에 익숙하지 않은 학생들이라 그런지 크기가 $10^9$인 배열을 만드는 팀이 많이 보였습니다. $N \leq 10^{100}$으로 했어야 하나… 라는 후회를 하고 있습니다. 본선 문제 중 가장 좋은 문제라고 생각합니다.</p> <h3 id="본선-f---시간딱딱충">본선 F - 시간딱딱충</h3> <p>원래는 구현이 귀찮은 문제를 의도하고 만들었는데, 어쩌다 보니 구현은 깔끔하고 지문이 어지러운 문제가 되었습니다. 지문이 무섭게 생겨서 늦게 풀릴 줄 알았는데 대회 시작 23분 만에 풀려서 놀랐습니다.</p> <p>출제자는 대회에서 3번째로 빨리 풀렸고, 정답률(1제출 1AC, 100%)이 가장 높기 때문에 쉬운 문제라고 주장하던데… 저는 잘 모르겠습니다.</p> <h3 id="본선-g---인공-신경망">본선 G - 인공 신경망</h3> <p>원래 작년 천하제일 코딩대회에 나올 예정이었지만 Conv1D에게 자리를 뺏겨서 올해 나오게 되었습니다. 중학생 때 신경망을 공부하면서 왜 activation function을 넣어야 하는지 의문을 가졌었는데, 그때의 기억을 되살려서 만든 문제입니다.</p> <p>신경망 전체를 퍼셉트론 하나로 압축하는 문제인데, naive한 풀이로 시도하는 팀들이 많아서 안타까웠습니다.</p> <h3 id="본선-h---최대-최소공배수">본선 H - 최대 최소공배수</h3> <p>구글에 maximize lcm of three numbers 처럼 검색하면 바로 풀이가 나오는 문제입니다. 검색이 허용되는 대회라서 쉽게 풀라고 낸 문제인데, 많이 안 풀려서 당황스러웠습니다. 대회장을 돌아다니면서 보니 한글로 검색하는 팀은 몇 팀 있었는데 영어로 검색하는 팀이 없는 것 같았습니다. 문제 해설할 때 검색의 중요성을 강조했습니다.</p> <h3 id="본선-i---최장-최장-증가-부분-수열">본선 I - 최장 최장 증가 부분 수열</h3> <p>원래 2D Segment Tree 쓰는 문제로 선린 정보 올림피아드에 낼 생각이었지만, 너무 재미없는 것 같아서 간단한 DP로 풀 수 있도록 $O(N^4)$로 너프하고 천하제일 코딩대회에 출제했습니다. 더 어려운 DP 문제인 예선 E를 푼 사람이 꽤 있어서 많이 풀릴 줄 알았는데 많이 안 풀려서 슬펐습니다.</p> <h3 id="본선-j---행성-정렬">본선 J - 행성 정렬</h3> <p>쉬운 문제로 만들고 싶어서 입력 제한을 정할 때 많은 고민을 했습니다. 가능한 풀이로는 유클리드 호제법($O(N \log X)$), 소인수 분해($O(N \sqrt X)$), 브루트포스($O(NX)$) 등이 있는데, 많은 고민 끝에 유클리드 호제법과 소인수 분해만 통과시키는 방향으로 제한을 정했습니다. 근데 다들 유클리드 호제법으로 잘 푼 거 보면… 괜한 고민을 한 것 같습니다.</p> <h3 id="마무리">마무리</h3> <p>2주 동안 쉬지도 못하고 일만 했습니다. 지금까지 대회만 40번 넘게 운영했는데, 가장 힘들었던 대회 3개를 선택하라고 하면 주저하지 않고 이 대회를 선택할 것 같습니다. 그만큼 대회에 큰 애정을 갖고 있다고 받아들이면 좋을 것 같습니다.<br />이걸 내년에도 해야 한다는 걸 생각해 보면 눈앞이 깜깜해지는데… 그건 1년 뒤의 저에게 미뤄두고 지금은 잠시 휴식을 취하려고 합니다. 사실 다음 학기에 선린 정보 올림피아드도 출제해야 합니다.</p> <p>저와 같이 대회 문제 작업을 한 출제진과 검수진, 대회 현장에서 열심히 힘써주신 후배들과 선생님들, 그리고 대회와 오픈 콘테스트에 참여해 주신 많은 분들, 정말 감사드립니다.</p> <p>끝!</p>JusticeHui서론 지난 2년간 온라인으로 진행되었던 천하제일 코딩대회가 3년 만에 오프라인으로 돌아왔습니다. 코로나로 인해 멈춰있던 학교 행사의 시작을 함께 하게 되어서 영광이었습니다.작년에는 단순히 문제만 만들면 됐지만 올해는 오프라인 대회이기 때문에 문제지, 풍선, 자리 배치 등 신경 써야 할 요소가 많았습니다. 그럼에도 불구하고 잘 따라와 준 다른 출제진, 현장에서 열심히 힘을 써준 후배님들과 학교 선생님들께 이 자리를 빌려 감사하다는 말씀 전하고 싶습니다.2022 KOI 1차대회 고등부 문제 풀이2022-06-09T00:00:00+00:002022-06-09T00:00:00+00:00https://justicehui.github.io/koi/2022/06/09/koi-2022-1<h3 id="총평-및-문제-감상">총평 및 문제 감상</h3> <p>이제 대학생이라 KOI에 참가하지 못하지만, 그래도 제가 한동안 정말 열심히 준비했던 대회인 만큼 풀이는 지속적으로 작성할 생각입니다.</p> <ul> <li><a href="/koi/2020/09/21/koi-2020-1/">2020 KOI 1차대회 고등부 문제 풀이</a></li> <li><a href="/koi/2021/05/17/koi-2021-1/">2021 KOI 1차대회 고등부 문제 풀이</a></li> </ul> <p>작년에 이어서 올해도 1교시 난이도가 상승했습니다. 사고력 문제 유형(1~12번)의 난이도는 작년에 비해 조금 어려워졌고, 비버 챌린지 유형(13~20번)의 난이도가 많이 올랐습니다. 작년에 나온 Sprague-Grundy Theorem, Burnside’s Lemma와 같은 어려운 개념을 묻는 문제는 없지만, 풀이를 생각하는 난이도와 정답을 구하기 위해 필요한 계산량이 모두 증가했습니다. 앞으로도 계속 난이도가 올라간다면 시간 분배와 멘탈 관리가 중요해질 것 같습니다.</p> <p>작년에 이어서 올해도 1-5, 1-13처럼 과거 지역 예선(2017년 이전 대회)에 자주 나왔던 유형의 문제가 다시 출제되었습니다. <a href="http://www.comschool.co.kr/lms/examlist.php">이 사이트</a>에서 과거 지역 예선 기출문제를, <a href="/tag/#/KOI-Regional">여기</a>에서 2014 ~ 2017년 수학 문제 풀이를 볼 수 있으니, 대회 준비할 때 참고하면 좋을 것 같습니다.</p> <p>지난 2년 동안 KOI 1차 대회 풀이를 올리면서, 1교시 대비 방법에 대한 조언을 달라는 연락을 많이 받았습니다. 비버 챌린지 교재를 구매하거나 기출문제를 이용해 연습하는 분들을 많이 봤는데, 개인적으로 이 방법을 추천하진 않습니다. 지금까지의 KOI 기출문제를 보면 실제 비버 챌린지 문제와는 스타일이 조금 다르고, 오히려 실기 문제와 비슷한 문제가 많습니다. 컴퓨터가 해야 하는 계산을 손으로 해야 하는 부분만 빼면 크게 다르지 않습니다. 따라서 저는 비버 챌린지 기출로 대비하는 것보다는 온라인 저지 사이트에서 다양한 문제를 많이 풀어보는 것을 추천합니다.</p> <p>2교시는 사람마다 난이도가 다르게 느껴질 것 같습니다. 특히 1교시 문제가 어려웠기 때문에 멘탈이 무너진 학생은 더 어렵게 느껴졌을 것이라 생각합니다. 작년/재작년 실기 문제와 유형이 조금 다른 점도 한몫한 것 같습니다.</p> <p>저도 경험해 봐서 알지만, 멘탈이 약한 건 고치기 어렵습니다. 멘탈이 무너지지 않도록 여러 장치를 마련하는 것이 중요합니다. $x$분 이상 안 풀리면 다음 문제로 넘어가기, 대회 종료 $y$분 전부터는 부분 점수만 노리기, 모든 문제를 다 읽고 시작하기 같은 자신만의 규칙을 세워서 멘탈이 무너지지 않도록 전략을 미리 만드는 것을 추천합니다.</p> <h3 id="문제-유형">문제 유형</h3> <table> <thead> <tr> <th>문제</th> <th>유형</th> <th>문제</th> <th>유형</th> <th>문제</th> <th>유형</th> <th>문제</th> <th>유형</th> </tr> </thead> <tbody> <tr> <td>1번</td> <td>위상정렬</td> <td>2번</td> <td>애드혹</td> <td>3번</td> <td>완전탐색</td> <td>4번</td> <td>DP</td> </tr> <tr> <td>5번</td> <td>확률</td> <td>6번</td> <td>DP</td> <td>7번</td> <td>그리디</td> <td>8번</td> <td>경우의 수</td> </tr> <tr> <td>9번</td> <td>DP</td> <td>10번</td> <td>정수론</td> <td>11번</td> <td>DP/게임 이론</td> <td>12번</td> <td>경우의 수</td> </tr> <tr> <td>13번</td> <td>그래프 이론</td> <td>14번</td> <td>그리디</td> <td>15번</td> <td>그래프 이론</td> <td>16번</td> <td>게임 이론</td> </tr> <tr> <td>17번</td> <td>정수론</td> <td>18번</td> <td>애드혹</td> <td>19번</td> <td>휴리스틱</td> <td>20번</td> <td>애드혹</td> </tr> <tr> <td>실기 1번</td> <td>정렬</td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> <tr> <td>실기 2번</td> <td>그리디</td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> <tr> <td>실기 3번</td> <td>세그먼트 트리<br />그리디</td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> </tbody> </table> <h3 id="1-1-달리기-5점">1-1. 달리기 (5점)</h3> <p>B는 꼴등이고, A는 C와 D보다 순위가 낮습니다. E는 B와 A 사이에 있어야 하므로 A, E, B가 각각 3등, 4등, 5등입니다.</p> <h3 id="1-2-거스름돈-5점">1-2. 거스름돈 (5점)</h3> <p>현재 갖고 있는 동전으로 만들 수 있는 금액의 집합을 $S$를 알고 있을 때, $x$원 짜리 동전을 추가해서 만들 수 있는 금액의 집합 $S’$을 구하는 방법을 알아봅시다.<br />7원 짜리 동전만 이용해 만들 수 있는 집합 $S = \lbrace 7, 14, 21, 28, \cdots \rbrace$에 $x = 9$원 짜리 동전을 추가하는 경우를 예시로 설명하겠습니다.</p> <p>먼저 1부터 적당한 수까지 한 줄에 $x(=9)$개씩 적은 다음, $S$에 포함된 원소를 표시합시다.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 1 2 3 4 5 6 7(O) 8 9 10 11 12 13 14(O) 15 16 17 18 19 20 21(O) 22 23 24 25 26 27 28(O) 29 30 31 32 33 34 35(O) 36 37 38 39 40 41 42(O) 43 44 45 46 47 48 49(O) 50 51 52 53 54 55 56(O) 57 58 59 60 61 62 63(O) </code></pre></div></div> <p>한 줄에 $x(=9)$개씩 적었기 때문에, $S$에 속한 원소의 아래에 적힌 수들은 $x$원 짜리 동전을 몇 개 더 사용해서 만들 수 있습니다. 그러므로 표시된 원소의 밑에 위치한 수들을 표시합시다. $x, 2x, 3x, \cdots$도 표시하는 것을 잊지 마세요.<br />이 과정을 통해 7원 짜리와 9원 짜리 동전으로 48 이상의 모든 정수를 만들 수 있다는 것을 알 수 있습니다.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 1 2 3 4 5 6 7(O) 8 9(O) 10 11 12 13 14(O) 15 16(X) 17 18(X) 19 20 21(O) 22 23(X) 24 25(X) 26 27(X) 28(O) 29 30(X) 31 32(X) 33 34(X) 35(O) 36(X) 37(X) 38 39(X) 40 41(X) 42(O) 43(X) 44(X) 45(X) 46(X) 47 48(X) 49(O) 50(X) 51(X) 52(X) 53(X) 54(X) 55(X) 56(O) 57(X) 58(X) 59(X) 60(X) 61(X) 62(X) 63(O) </code></pre></div></div> <p>동일한 방법으로 11원 동전을 추가할 수 있고, 정답은 27입니다.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 1 2 3 4 5 6 7(O) 8 9(O) 10 11(O) 12 13 14(O) 15 16(O) 17 18(O) 19 20(X) 21(O) 22(X) 23(O) 24 25(O) 26 27(O) 28(O) 29(X) 30(O) 31(X) 32(O) 33(X) 34(O) 35(O) 36(O) 37(O) 38(X) 39(O) 40(X) 41(O) 42(O) 43(O) 44(O) </code></pre></div></div> <h3 id="1-3-블록-쌓기-6점">1-3. 블록 쌓기 (6점)</h3> <p>$L \leq W$인 경우만 생각해도 됩니다. 첫번째 블록은 $(2,5,8), (2,8,5), (5,8,2)$, 두번째 블록은 $(4,4,9), (4,9,4)$, 세번째 블록은 $(2,3,4), (2,4,3), (3,4,2)$가 가능합니다. 세 블록의 상태를 결정한 뒤($3\cdot2\cdot3=18$가지), 조건을 만족하도록 블록을 배열할 수 있는 경우 높이를 구하면 됩니다.<br />$(4,9,4), (2,5,8), (2,3,4)$를 차례로 쌓으면 높이를 16으로 만들 수 있습니다.</p> <h3 id="1-4-점-잇기-6점">1-4. 점 잇기 (6점)</h3> <p>점이 $2k$개 있을 때의 정답을 $D(k)$라고 하고, 1번 점과 연결되는 점을 보면서 점화식을 계산합시다.</p> <ul> <li>1번 점과 2번 점 연결: 3, 4, 5, 6, 7, 8번 점을 연결해야 함 → $D(4) \leftarrow D(3)$</li> <li>1번 점과 4번 점 연결: 2, 3번 점을 연결하고 5, 6, 7, 8번 점을 연결해야 함 → $D(4) \leftarrow D(1) \times D(2)$</li> <li>1번 점과 6번 점 연결: 2, 3, 4, 5번 점을 연결하고 7, 8번 점을 연결해야 함 → $D(4) \leftarrow D(2) \times D(1)$</li> <li>1번 점과 8번 점 연결: 2, 3, 4, 5, 6, 7번 점을 연결해야 함 → $D(4) \leftarrow D(3)$</li> </ul> <p>즉, $D(4) = 2\cdot D(3) + 2\cdot D(1)D(2)$입니다. $D(1) = 1, D(2) = 2$라는 것은 쉽게 알 수 있고, 동일한 방법으로 $D(3) = 5$를 계산한 다음 $D(4) = 14$를 계산할 수 있습니다.</p> <h3 id="1-5-구슬-뽑기-7점">1-5. 구슬 뽑기 (7점)</h3> <p>사건 $A$가 일어났다는 가정 하에 사건 $B$가 일어날 확률은 $P(B\vert A) = \frac{P(A\cap B)}{P(A)}$로 계산할 수 있습니다.<br />4개의 상자 중 한 곳에서 무작위로 구슬을 1개 뽑을 때 검은색 구슬을 뽑을 확률은 $\frac{6}{12}$이고, 구슬을 2개 뽑을 때 모두 검은색 구슬일 확률은 $\frac{4}{12}$입니다. 그러므로 정답은 $\frac{2}{3}$입니다.</p> <h3 id="1-6-막대기-세우기-7점">1-6. 막대기 세우기 (7점)</h3> <p><a href="https://www.acmicpc.net/problem/1328">BOJ 1328 고층 빌딩</a>과 동일한 문제입니다.<br />왼쪽에서 $l$개, 오른쪽에서 $r$개의 막대가 보이도록 $i$개의 막대를 배치하는 경우의 수를 $D(i,l,r)$이라고 정의합시다. 높이가 가장 낮은 막대를 추가하는 과정을 통해 점화식을 세울 수 있습니다.</p> <ul> <li>가장 낮은 막대를 가장 왼쪽에 추가하는 경우: 왼쪽에서 보이는 막대의 개수 1 증가 → $D(i,l,r) \leftarrow D(i-1,l-1,r)$</li> <li>가장 낮은 막대를 가장 오른쪽에 추가하는 경우: 오른쪽에서 보이는 막대의 개수 1 증가 → $D(i,l,r) \leftarrow D(i-1,l,r-1)$</li> <li>나머지 경우($i-2$ 가지): 다른 막대에 가려지기 때문에 변하지 않음 → $D(i,l,r) \leftarrow (i-2)\cdot D(i-1,l,r)$</li> </ul> <p>점화식은 $D(i,l,r) = D(i-1,l-1,r) + D(i-1,l,r-1) + (i-2)\cdot D(i-1,l,r)$이고, 직접 $D(6,3,2)=105$를 계산하면 됩니다.</p> <h3 id="1-7-세-수의-곱-9점">1-7. 세 수의 곱 (9점)</h3> <p>세 수를 곱해서 양수가 나오는 경우는 양수를 3개 곱하는 경우와 양수 1개, 음수 2개를 곱하는 경우밖에 없습니다. 각 경우에 대해 절댓값이 큰 수를 선택해 곱하면 최댓값을 얻을 수 있습니다. 양수 3개를 곱하는 경우의 최댓값은 $6\cdot5\cdot4=120$이고, 양수 1개와 음수 2개를 곱하는 경우의 최댓값은 $6\cdot(-6)\cdot(-7)=252$입니다.</p> <h3 id="1-8-2310-9점">1-8. 2310 (9점)</h3> <p>$2310 = 2\times3\times5\times7\times11$입니다. 그러므로 이 문제는 5개의 소인수를 적당히 세 곳으로 분배하는 경우의 수를 세는 문제입니다.<br />$a, b, c$ 중 1이 2번 또는 3번 등장하는 경우를 제외하면 같은 값이 나올 일이 없기 때문에, 단순히 분배하는 경우의 수만 세도 정답을 구할 수 있습니다.</p> <ul> <li>소인수를 0 / 1 / 4로 분해하는 경우 : $5!/4! = 5$</li> <li>소인수를 0 / 2 / 3으로 분배하는 경우 : $5!/2!/3! = 10$</li> <li>소인수를 1 / 1 / 3으로 분배하는 경우 : $5!/3! = 20$, 이때 소인수가 1개인 자리가 2개 있으므로 2로 나눠야 함 $\rightarrow 10$</li> <li>소인수를 1 / 2 / 2로 분배하는 경우 : $5!/2!/2! = 30$, 이때 소인수가 2개인 자리가 2개 있으므로 2로 나눠야 함 $\rightarrow 15$</li> <li>$5 + 10 + 10 + 15 = 40$</li> </ul> <h3 id="1-9-초콜릿-10점">1-9. 초콜릿 (10점)</h3> <p>1번 칸부터 $i$번 칸까지만 포장했을 때의 최대 가격을 $D(i)$라고 합시다. $l$번 칸부터 $r$번 칸까지 한 묶음으로 포장했을 때의 가격을 $C(l,r)$라고 하면 $D(i) = \max\lbrace D(j-1) + C(j,i)\rbrace$입니다. 점화식을 직접 계산하면 문제를 해결할 수 있습니다.<br />$D = \lbrace -\infty,4,5,7,9,10,12,13,15,17,20,20,22,25 \rbrace$ (1-based)이므로 정답은 $D(14) = 25$입니다.</p> <h3 id="1-10-순열-거듭제곱-10점">1-10. 순열 거듭제곱 (10점)</h3> <p>순열 $a = [10,1,15,2,9,6,13,14,5,4,8,7,3,11,12]$의 거듭제곱 $a^k$에서 각 칸의 값이 어떻게 변하는지 살펴봅시다.</p> <ul> <li>$a[1]$은 $k$가 증가함에 따라 $10\rightarrow4\rightarrow2\rightarrow1\rightarrow10\rightarrow\cdots$을 반복합니다.</li> <li>$a[3]$은 $k$가 증가함에 따라 $15\rightarrow12\rightarrow7\rightarrow13\rightarrow3\rightarrow15\rightarrow\cdots$를 반복합니다.</li> <li>$a[5]$는 $k$가 증가함에 따라 $9\rightarrow5\rightarrow9\rightarrow\cdots$를 반복합니다.</li> <li>$a[6]$은 $k$에 관계 없이 $6$입니다.</li> <li>$a[8]$은 $k$가 증가함에 따라 $14\rightarrow11\rightarrow8\rightarrow14\rightarrow\cdots$를 반복합니다.</li> </ul> <p>순열을 사이클로 분할하면, $a^m = [2,4,15,10,9,6,13,8,5,1,11,7,3,14,12]$가 되는 $m$에 대한 조건을 얻을 수 있습니다.<br />먼저, $a[1]$의 값을 통해 $m$을 4로 나눈 나머지가 3이라는 사실을 알 수 있습니다. 동일한 방식으로 $m$을 5로 나눈 나머지는 1, $m$을 2로 나눈 나머지는 1, $m$을 3으로 나눈 나머지는 0이라는 사실을 알 수 있습니다.</p> <p>4가지 조건을 만족하는 가장 작은 $m$은 중국인의 나머지 정리를 이용해 구할 수 있습니다. 또는 정답이 $4, 5, 2, 3$의 최소공배수 이하라는 사실을 이용해 $60$까지의 모든 수를 확인해보는 방법도 가능합니다. 정답은 51입니다.</p> <h3 id="1-11-동전-게임-15점">1-11. 동전 게임 (15점)</h3> <p>자신의 플레이어가 턴을 시작할 시점에 동전이 $i$에 위치했을 때 무조건 승리할 수 있다면 $D(i) = 1$, 그렇지 않으면 $D(i) = 0$으로 정의합시다. $D(k-1) = D(k-2) = D(k-3) = 1$입니다.<br />만약 동전을 $i$에서 $D(j) = 0$인 $j$로 보낼 수 있다면 $D(i) = 1$이고, 어떠한 경우에도 $D(j) = 0$인 $j$로 보낼 수 없으면 $D(i) = 0$입니다. $D(0) = 1$이면 먼저 시작하는 사람인 영희가 이기고, $D(0) = 0$이면 철수가 이깁니다.</p> <p>베스킨라빈스 31 게임의 필승법을 생각하면 $k = 22, 24$인 경우는 바로 해결할 수 있습니다. $k = 32$인 경우에는 28이 7의 배수이기 때문에 베스킨라빈스 31 게임의 필승법을 그대로 적용하지 못하므로 직접 계산해야 합니다.<br />$k = 32$인 경우, $D = \lbrace1,1,0,1,1,1,0,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,0,1,1,1,0\rbrace$ (0-based)입니다.</p> <h3 id="1-12-아이템-배치-15점">1-12. 아이템 배치 (15점)</h3> <p>출발 지점에서 도착 지점까지 가는 경로는 크게 위, 아래, 가운데로 가는 세 가지로 구분할 수 있습니다.</p> <p><img src="https://i.imgur.com/dAqzTgJ.png" alt="" /></p> <p>각 경로마다 항상 통과해야 하는 칸을 A, B, C, 어떤 경로로 이동하더라도 절대 통과하지 않는 칸을 ?로 표시해 보겠습니다. 빨간색으로 적혀있는 A와 B는 가운데로 지나는 경로에도 간섭하기 때문에 주의해서 계산해야 합니다.<br />?로 표시된 두 칸은 통과할 일이 없기 때문에 계산에서 제외한 뒤, 최종 결과에 $2^2 = 4$를 곱하도록 합시다.</p> <p><img src="https://i.imgur.com/RKs0TO0.png" alt="" /></p> <p>위/아래/가운데로 가는 경로에서 각각 서로 다른 아이템을 먹도록 하는 경우부터 고려합시다. 즉, 아래 그림에서 회색으로 칠해지지 않은 칸에만 아이템을 배치하겠습니다.<br />무조건 지나야 하는 한 칸에 아이템을 배치할 수도 있고, 혹은 대각선 방향으로 아이템을 배치해서 그중 정확히 하나를 가져가도록 할 수도 있습니다. 위로 가는 경로에서 6가지, 아래로 가는 경로에서 6가지, 가운데로 가는 경로에서 6가지를 선택할 수 있으므로, 이 경우에는 $6\times6\times6=216$가지를 선택할 수 있습니다.</p> <p><img src="https://i.imgur.com/cdMaW8F.png" alt="" /></p> <p>이제, 세 종류의 경로를 한 번에 커버하는 경우를 고려합시다. 즉, 위 그림에서 회색으로 칠해진 칸을 포함하도록 몇 개의 아이템을 배치할 것입니다.<br />이 경우는 아래 그림처럼 6가지의 방법이 있습니다.</p> <p><img src="https://i.imgur.com/BjXiOkQ.png" alt="" /></p> <p>?로 표시된 칸을 고려하지 않은 경우의 수는 $216 + 6 = 222$가지입니다. 여기에 ?로 표시된 두 칸에 아이템을 배치하는 방법의 수 $2^2 = 4$를 곱하면 $222\times4=888$을 얻을 수 있습니다.</p> <h3 id="1-13-한붓-그리기-8점">1-13. 한붓 그리기 (8점)</h3> <p>한붓 그리기가 가능할 필요 충분 조건은 <strong>차수가 홀수인 정점이 0개 또는 2개 존재하는 것</strong>입니다. 주어진 그래프의 각 정점의 차수는 각각 $1, 1, 2, 3, 3, 3, 3, 4$입니다. 차수가 홀수인 정점이 6개이므로, 이들을 2개씩 간선으로 짝을 지으면 3개의 간선을 이용해 한붓 그리기가 가능하도록 만들 수 있습니다.</p> <p>여담으로, 올림피아드의 출제 범위를 벗어나는 이야기지만 가중치 그래프에서 이 문제는 $O(\vert V\vert^3)$에 해결할 수 있습니다. <a href="https://koosaga.com/258">이 글</a>의 <strong>1. Chinese Postperson Problem</strong> 문단을 참고하세요.</p> <h3 id="1-14-수열-만들기-8점">1-14. 수열 만들기 (8점)</h3> <p>0이 등장하지 않는 가장 긴 구간을 찾은 다음, 뺄 수 있는 가장 큰 값(구간의 최솟값)을 빼는 것을 반복하는 것이 최적입니다. 10번 만에 문제에서 제시한 수열을 만들 수 있습니다.</p> <h3 id="1-15-트리-순회-8점">1-15. 트리 순회 (8점)</h3> <p>어느 한 곳으로 들어갔다가 다시 나오는 것은 되도록 피하는 것이 좋습니다. 그러므로, 기본적으로 트리의 지름을 따라가면서 남는 이동 횟수를 적당히 소모하는 것이 최적입니다.<br />트리의 지름을 따라 이동하면 8번의 이동으로 9개의 정점을 방문하게 되고, 중간에 10번 더 이동할 수 있습니다. $n$개의 정점을 추가로 방문하기 위해 들어갔다 나오는데 $2n$번의 이동이 필요하므로 5개의 정점을 추가로 방문하면 문제를 해결할 수 있습니다.</p> <h3 id="1-16-돌무더기-12점">1-16. 돌무더기 (12점)</h3> <p>플레이어는 바구니 A에서 1개 또는 2개 가져가거나, B에서 1개를 가져갈 수 있습니다. 반대로 컴퓨터는 A에서 1개를 가져가거나, B에서 1개 또는 2개 가져갈 수 있습니다.<br />만약 바구니 B를 비울 수 있다면, 컴퓨터는 바구니 A에서 1개씩만 가져갈 수 있으므로 홀짝을 적당히 조절해서 항상 A가 이기도록 만들 수 있습니다.</p> <p>일단 바구니 B에서 돌을 1개씩 가져가서 바구니 B를 비워냅시다. 만약 컴퓨터가 바구니 A에서 하나씩 가져가서 A가 한 턴 먼저 비워진다면, 플레이어는 바구니 B에 남은 마지막 돌을 가져가는 것으로 승리할 수 있습니다.</p> <p>그렇지 않은 경우, 즉 바구니 A에만 돌이 남게 된 상황을 생각합시다. 바구니 B가 비워진 다음 <strong>처음으로 플레이어의 턴</strong>이 돌아오면 바구니 A에는 1개 이상의 돌이 있습니다. 만약 짝수 개의 돌이 있으면 2개를 가져가고 홀수 개의 돌이 있다면 1개를 가져가서 돌을 짝수 개로 만듭시다.<br />컴퓨터가 돌을 가져가면 홀수 개가 되고, 그 다음부터는 항상 1개씩 가져가면 플레이어가 마지막 돌을 가져가서 승리할 수 있습니다.</p> <p>상대방의 선택지를 제한하고, 상대방의 전략에 맞춰 간다는 생각으로 전략을 세우면 됩니다.</p> <h3 id="1-17-최대공약수-12점">1-17. 최대공약수 (12점)</h3> <p>$a, b$의 최대공약수 $\gcd(a,b)$에 대해 아래 4가지가 성립합니다.</p> <ul> <li>$\gcd(a,0) = a$</li> <li>$a \geq b$이면 $\gcd(a,b) = \gcd(a-b, b)$</li> <li>$\gcd(2a,2b) = 2\times\gcd(a,b)$</li> <li>$a$가 홀수면 $\gcd(a,2b) = \gcd(a,b)$</li> </ul> <p>이 성질들을 이용해 최대공약수를 구하는 방법을 알아봅시다.</p> <ol> <li>먼저 $a, b$가 모두 짝수라면 둘 중 하나 이상이 홀수가 될 때까지 2로 나누고, 나눈 횟수 $k$를 기억합시다. <ul> <li>최대 $O(\log \min(a,b))$번의 나눗셈을 수행합니다.</li> <li>$a, b$를 2로 여러 번 나눠서 얻은 값을 $a’, b’$이라고 하면, $\gcd(a,b) = 2^k\gcd(a’,b’)$입니다.</li> </ul> </li> <li>$a, b$ 중 하나 이상은 홀수입니다. 둘 중 짝수가 있다면 홀수가 될 때까지 2로 나눕니다. <ul> <li>이 과정에서 최대공약수는 변하지 않습니다.</li> </ul> </li> <li>두 수가 모두 홀수가 되었다면 큰 수에서 작은 수를 뺍니다. <ul> <li>이 과정에서 최대공약수는 변하지 않습니다.</li> </ul> </li> <li>0이 나올 때까지 2~3번 과정을 반복합니다. <ul> <li>이 과정은 최대 $O(\log \max(a,b))$번 반복합니다.</li> </ul> </li> <li>둘 중 0이 아닌 값에 $2^k$를 곱한 결과가 최대공약수입니다.</li> </ol> <p>이 과정을 직접 수행하면 주어진 연산만 사용해서 문제를 해결할 수 있습니다. 이 방법은 Binary GCD Algorithm 또는 Stein’s Algorithm이라는 이름으로 알려져 있습니다.</p> <h3 id="1-18-거짓말-13점">1-18. 거짓말 (13점)</h3> <p>만약 두 사람 $A, B$의 속성만 알아낼 수 있다면, 다른 사람들의 속성는 $A \neq B$ 질문의 결과로 알아낼 수 있습니다. 두 사람의 속성을 특정하는 방법을 찾아봅시다.</p> <p>$a, b$에게 동일하게 $A \neq B$인지 물어봅시다. 만약 $a$와 $b$의 답변이 동일하면 $a = b$이고, 둘의 답변이 다르면 $a\neq b$입니다.<br />이제 $A, B$에게 $a\neq b$인지 물어봅시다. 우리는 이 질문의 정답을 알고 있기 때문에 $A$와 $B$의 속성을 알아낼 수 있습니다. 그러므로 4명만 있어도 두 사람 $A, B$의 속성을 알아낼 수 있습니다.</p> <p>1, 2번 사람에게 $3\neq 4$인지 물어보고, 다른 모든 사람에게 $1\neq 2$인지 물어본 다음, 위에서 설명한 방법에서 $A=1,B=2,a=3,b=4$를 대입해서 정답을 구하면 됩니다.</p> <h3 id="1-19-격자판-장식하기-15점">1-19. 격자판 장식하기 (15점)</h3> <p>삼각형의 세 꼭짓점 중 두 개의 문양이 결정되었다면 나머지 하나는 바로 결정할 수 있습니다. 왼쪽 아래에 있는 삼각형부터 시작해 봅시다.</p> <p><img src="https://i.imgur.com/AXGAvNq.png" alt="" /></p> <p>J 영역의 간선을 역슬래시로 놓고 문양을 채워 봅시다. G 영역에서 간선을 만들 수 없기 때문에 J 영역에 역슬래시 모양의 간선을 넣으면 안 된다는 것을 알 수 있습니다.</p> <p><img src="https://i.imgur.com/qb6KtT4.png" alt="" /></p> <p>J 영역에 슬래시 모양의 간선을 넣고 문양을 채웁시다. G 영역의 간선도 함께 채울 수 있습니다.</p> <p><img src="https://i.imgur.com/o4nWWdP.png" alt="" /></p> <p>이제 A 영역의 간선을 결정해 봅시다. 일단 슬래시 모양의 간선을 넣어보겠습니다. <code class="language-plaintext highlighter-rouge">A,B,D,H,K,I,L,E,F</code> 영역의 간선을 순서대로 결정할 수 있고, 빨간색으로 표시한 부분에서 조건을 만족하지 않는 간선이 등장합니다.</p> <p><img src="https://i.imgur.com/ADFxkyt.png" alt="" /></p> <p>A 영역에 역슬래시 모양의 간선을 넣읍시다. <code class="language-plaintext highlighter-rouge">A,B,D,H,K,I,L,E,F,C</code> 영역의 간선을 순서대로 결정할 수 있고, 문제에서 요구하는 정답을 얻을 수 있습니다.</p> <p><img src="https://i.imgur.com/2ejZ9wM.png" alt="" /></p> <h3 id="1-20-괄호-문자열-20점">1-20. 괄호 문자열 (20점)</h3> <p>만들고자 하는 괄호 문자열을 고정하면, 이를 만드는데 필요한 교환 횟수는 <strong>(원본 문자열과 목표 문자열의 문자가 다른 위치의 수) / 2를 올림한 값</strong> 입니다. 교환할 때마다 2글자가 맞춰지기 때문에 (문자가 다른 위치의 수)를 2로 나눈 나머지가 최소 횟수입니다. 만약 그러한 위치의 개수가 홀수인 경우, 구간에 포함되지 않은 문자 하나를 바꿔야 하기 때문에 (위치의 개수 + 1) / 2, 즉 위치의 개수를 2로 나눈 나머지를 올림한 값이 정답이 됩니다.</p> <p>만약 구간 $[s, e]$가 $[s’,e’]$을 포함한다면, $[s’,e’]$과 $[s,e]\setminus[s’,e’]$가 각각 올바른 괄호 문자열이 되도록 만들면 됩니다. 만약 구간 $[s,e]$와 $[s’,e’]$이 겹치는 부분이 있다면($s \leq s’ \leq e \leq e’$이라고 가정), $[s,s’-1], [s’,e], [e+1,e’]$이 각각 올바른 괄호 문자열이 되도록 만들면 됩니다.<br />겹치는 구간들을 잘라내면 고려해야 하는 구간의 크기를 줄일 수 있습니다.</p> <p>각 구간마다 독립적으로 목표 문자열을 만들어도 됩니다. 구간의 크기가 충분히 작기 때문에 “원본 문자열과 목표 문자열이 다른 위치의 수”를 최소화하는 목표 문자열은 직접 구할 수 있습니다.</p> <p>아래 텍스트는 제가 구한 답안입니다. 첫째 줄은 원본 문자열, 둘째 줄부터는 각 구간의 목표 문자열입니다.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># 1 )()())(()((()) (()) 2 ()() 2 ()(()) 2 (2+2+2)/2 = 3 # 2 ))))(())))((((()((() (())------ 2 ((()))---------- 1 ((((())))) 3 (2+1+3)/2 = 3 # 3 (()()()))()(())( ((--------)) 1 ((----)) 2 (()) 1 (--) 1 () 1 (1+2+1+1+1)/3 = 3 # 4 )))))))))))))((((((((((((( (------------------------) 2 ()(------)() 3 ((())) 3 --(----------) 1 ()()-- 2 ()()() 3 (2+3+3+1+2+3)/2 = 7 # 5 )()()))))())(()((()()))(((((() ()(--------((------))------) 1 (())(()) 3 ((())) 3 ((())) 4 (1+3+3+4)/2 = 5.5 -&gt; 6 (마지막 글자를 '('로 바꿔야 함) </code></pre></div></div> <h3 id="2-1-피하자">2-1. 피하자</h3> <p>두 가지 풀이가 있고, 두 풀이 모두 좋은 풀이이므로 공부하는 것을 권장합니다.</p> <h4 id="풀이-1---공식-풀이와-동일">풀이 1 - 공식 풀이와 동일</h4> <p>주어진 원소의 값이 아닌 2로 나눈 나머지만 고려해도 충분합니다. 그러므로 0과 1로만 구성된 배열이라고 생각합시다.</p> <p>홀수와 짝수가 인접한 경우가 0번 등장하는 경우는 모든 원소가 0이거나 모든 원소가 1인 경우밖에 없습니다. 1번 등장하는 경우는 앞에 0이 모두 등장한 다음 뒤에 1이 등장하는 경우와 그 반대의 경우가 있습니다. 결국, 이 문제는 배열을 $[0,0,\cdots,0,1,1,\cdots,1]$ 또는 $[1,1,\cdots,1,0,0,\cdots,0]$ 꼴로 만드는 문제라고 생각할 수 있고, 배열을 오름차순 또는 내림차순으로 정렬하는 문제가 됩니다.</p> <p>오름차순으로 정렬하는 경우만 생각합시다. 내림차순으로 정렬하는 것은 동일한 방법으로 할 수 있습니다.<br />인접한 원소를 교환하면서 배열을 오름차순으로 정렬할 때, 필요한 교환의 최소 횟수는 $i &lt; j \text{ and } A_i &gt; A_j$를 만족하는 순서쌍 $(i, j)$의 개수와 같습니다. 배열의 크기가 최대 $10^6$으로 매우 크기 때문에 모든 $(i,j)$ 쌍을 확인하는 것으로는 문제를 해결할 수 없습니다.</p> <p>이 문제에서 $i &lt; j \text{ and } A_i &gt; A_j$이면 $A_i = 1, A_j = 0$를 만족하기 때문에, 조건을 만족하는 순서쌍 $(i,j)$의 개수는 $A_j = 0$인 $j$에 대해 자신보다 앞에 있는 $1$의 개수의 합이라고 생각할 수 있습니다. 이는 <strong>지금까지 등장한 1의 개수</strong>를 관리하면 $O(N)$에 계산할 수 있습니다.<br />그러므로 오름차순으로 정렬하는데 필요한 필요한 교환 횟수를 $O(N)$ 시간에 구할 수 있고, 동일한 방법으로 내림차순 정렬도 $O(N)$ 시간에 처리할 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="mi">1010101</span><span class="p">];</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">R</span><span class="o">=</span><span class="mf">1e18</span><span class="p">;</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">%=</span> <span class="mi">2</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">iter</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">iter</span><span class="o">&lt;</span><span class="mi">2</span><span class="p">;</span> <span class="n">iter</span><span class="o">++</span><span class="p">){</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">cnt</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">acc</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">iter</span><span class="p">)</span> <span class="n">acc</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">else</span> <span class="n">cnt</span> <span class="o">+=</span> <span class="n">acc</span><span class="p">;</span> <span class="p">}</span> <span class="n">R</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">R</span><span class="p">,</span> <span class="n">cnt</span><span class="p">);</span> <span class="p">}</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">R</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <h4 id="풀이-2---별해">풀이 2 - 별해</h4> <p>$i$번째에 있는 수를 $j$번째로 옮기기 위해서는 인접한 원소를 $\vert i-j\vert$번 교환해야 합니다. 같은 값을 가진 원소끼리 서로 역전하면 항상 손해이기 때문에 역전하지 않는 경우, 즉 서로의 상대적인 순서를 유지하는 경우만 생각해도 됩니다.</p> <p>입력에서 0이 등장한 위치를 $X_1, X_2, \cdots, X_k$, 1이 등장한 위치를 $Y_1, Y_2, \cdots, Y_{N-k}$라고 합시다. 배열을 오름차순으로 정렬하기 위해서는 $X_i$는 $i$번째로 이동해야 하고, $Y_i$는 $k+i$로 이동해야 합니다. 그러므로 각 원소들의 이동 거리의 합은 $\sum \vert X_i - i\vert + \sum \vert Y_i-(k+1)\vert$가 됩니다.</p> <p>이때 인접한 두 원소를 교환할 때마다 원소 2개의 위치가 1씩 바뀌기 때문에, 위에서 계산한 <strong>이동 거리의 합을 2로 나눈 값</strong>이 문제의 정답이 됩니다. 이 방법을 사용해도 $O(N)$ 시간에 해결할 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="mi">1010101</span><span class="p">];</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">R</span><span class="o">=</span><span class="mf">1e18</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">V</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">V</span><span class="p">[</span><span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">%</span><span class="mi">2</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">iter</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">iter</span><span class="o">&lt;</span><span class="mi">2</span><span class="p">;</span> <span class="n">iter</span><span class="o">++</span><span class="p">){</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">now</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">cnt</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">2</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="n">j</span> <span class="o">:</span> <span class="n">V</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="n">now</span> <span class="o">+=</span> <span class="n">abs</span><span class="p">(</span><span class="o">++</span><span class="n">cnt</span> <span class="o">-</span> <span class="n">j</span><span class="p">);</span> <span class="p">}</span> <span class="n">R</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">R</span><span class="p">,</span> <span class="n">now</span><span class="p">);</span> <span class="n">swap</span><span class="p">(</span><span class="n">V</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span> <span class="p">}</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">R</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <h3 id="2-2-abbc">2-2. ABBC</h3> <p>세 가지 풀이가 있습니다. 풀이 3에 사용되는 개념은 올림피아드에 자주 등장하는 주제는 아니지만, 알고리즘을 깊게 공부하고자 하는 학생이라면 공부하는 것을 추천합니다.</p> <h4 id="풀이-1---on-풀이">풀이 1 - $O(N)$ 풀이</h4> <p>$B$는 $A$와 매칭될 수도 있고 $C$와 매칭될 수도 있습니다. 이때 $A$와 매칭할 때 사용할 $B$는 뒤에 있는 것부터 사용하는 것이 좋고, $C$와 매칭할 때 사용할 $B$는 앞에 있는 것부터 사용하는 것이 좋습니다.<br />일단 지금은 $C$를 생각하지 말고, 뒤에 있는 $B$부터 차례로 보면서 자신보다 앞에 있는 가장 가까운 $A$와 매칭합시다. 이렇게 하면 $A-B$ 매칭의 개수가 최대가 되고, 이 과정은 투 포인터를 이용해 $O(N)$에 할 수 있습니다. 이후 $A$와 매칭이 안 된 $B$를 차례로 보면서 자신보다 뒤에 있는 $C$와 매칭하면 됩니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="kt">int</span> <span class="n">N</span><span class="p">;</span> <span class="n">string</span> <span class="n">S</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">V</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">S</span><span class="p">;</span> <span class="n">N</span> <span class="o">=</span> <span class="n">S</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">V</span><span class="p">[</span><span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">-</span><span class="sc">'A'</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> <span class="kt">int</span> <span class="n">res</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">size</span><span class="p">()</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">j</span><span class="o">=</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">V</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">size</span><span class="p">()</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&gt;=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">--</span><span class="p">){</span> <span class="k">while</span><span class="p">(</span><span class="n">j</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">j</span><span class="p">])</span> <span class="n">j</span><span class="o">--</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">j</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="n">res</span><span class="o">++</span><span class="p">,</span> <span class="n">j</span><span class="o">--</span><span class="p">,</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">pop_back</span><span class="p">();</span> <span class="p">}</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">while</span><span class="p">(</span><span class="n">j</span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">size</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">V</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">i</span><span class="p">])</span> <span class="n">j</span><span class="o">++</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">j</span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">size</span><span class="p">())</span> <span class="n">res</span><span class="o">++</span><span class="p">,</span> <span class="n">j</span><span class="o">++</span><span class="p">;</span> <span class="p">}</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">res</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <h4 id="풀이-2---on-log-n-풀이">풀이 2 - $O(N \log N)$ 풀이</h4> <p>뒤에 있는 $a$개의 $B$는 $A$와 매칭할 때만 사용하고, 나머지 앞에 있는 $c=N-a$개의 $B$는 $C$와 매칭할 때만 사용한다고 합시다. $a$가 고정되어 있으면 풀이 1처럼 투 포인터를 이용해 $O(N)$에 최대 매칭을 구할 수 있습니다.<br />$a$가 고정되었을 때의 최대 매칭의 크기를 $f(a)$라고 하면, $f(a)$는 증가하다가 극댓값을 찍고 감소하는 형태임을 알 수 있습니다. 그러므로 삼분 탐색을 이용해 $O(N \log N)$에 문제를 해결할 수도 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="kt">int</span> <span class="n">N</span><span class="p">;</span> <span class="n">string</span> <span class="n">S</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">V</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span> <span class="kt">int</span> <span class="nf">f</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">){</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">;</span> <span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">size</span><span class="p">()</span> <span class="o">-</span> <span class="n">a</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">c</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">C</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">i</span><span class="p">]);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="n">c</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">a</span><span class="o">+</span><span class="n">c</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">A</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">i</span><span class="p">]);</span> <span class="kt">int</span> <span class="n">res</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">a</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">j</span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">size</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">V</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="n">res</span><span class="o">++</span><span class="p">,</span> <span class="n">j</span><span class="o">++</span><span class="p">;</span> <span class="p">}</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="n">c</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">j</span><span class="o">=</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">V</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">size</span><span class="p">()</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&gt;=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">--</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">j</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="n">j</span><span class="p">])</span> <span class="n">res</span><span class="o">++</span><span class="p">,</span> <span class="n">j</span><span class="o">--</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="n">res</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">S</span><span class="p">;</span> <span class="n">N</span> <span class="o">=</span> <span class="n">S</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">V</span><span class="p">[</span><span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">-</span><span class="sc">'A'</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> <span class="kt">int</span> <span class="n">l</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">r</span> <span class="o">=</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">size</span><span class="p">();</span> <span class="k">while</span><span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="mi">3</span> <span class="o">&lt;=</span> <span class="n">r</span><span class="p">){</span> <span class="kt">int</span> <span class="n">m1</span> <span class="o">=</span> <span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="n">l</span> <span class="o">+</span> <span class="n">r</span><span class="p">)</span> <span class="o">/</span> <span class="mi">3</span><span class="p">,</span> <span class="n">m2</span> <span class="o">=</span> <span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="n">r</span> <span class="o">+</span> <span class="n">r</span><span class="p">)</span> <span class="o">/</span> <span class="mi">3</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">f</span><span class="p">(</span><span class="n">m1</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">f</span><span class="p">(</span><span class="n">m2</span><span class="p">))</span> <span class="n">l</span> <span class="o">=</span> <span class="n">m1</span><span class="p">;</span> <span class="k">else</span> <span class="n">r</span> <span class="o">=</span> <span class="n">m2</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="n">res</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="n">l</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">r</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">res</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">f</span><span class="p">(</span><span class="n">i</span><span class="p">));</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">res</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <h4 id="풀이-3---별해">풀이 3 - 별해</h4> <p>시간 복잡도를 생각하지 않으면, 이 문제는 이분 매칭을 이용해 정답을 구할 수 있습니다. 각 문자를 정점으로 생각한 다음, 각 $B$마다 자신과 매칭 가능한 $A, C$들을 연결하면 정점이 $O(N)$개, 간선이 $O(N^2)$개 있는 이분 그래프를 만들 수 있습니다. Ford-Fulkerson Method을 기반으로 한 $O(VE)$ 알고리즘을 사용하면 $O(N^3)$, Hopcroft-Karp Algorithm을 이용하면 $O(E\sqrt V) = O(N^{2.5})$에 정답을 구할 수 있습니다. 이 풀이를 발전시켜 봅시다.</p> <p>그래프에서 각 $B$와 연결되는 $A$와 $C$는 각각 연속한 구간으로 나타낼 수 있습니다. 이렇게 어떤 정점을 <strong>구간에 속한 모든 정점</strong>과 연결하는 것은 <a href="/tutorial/2020/09/05/graph-with-segment-tree/">세그먼트 트리를 이용해 최적화</a> 할 수 있다는 것이 잘 알려져 있습니다. 잘 알려져 있지 않은 것 같다면 링크된 글로 이동해 공부해 보세요.<br />세그먼트 트리를 이용하면 정점 $O(N)$개, 간선 $O(N \log N)$개로 구성된 그래프를 얻을 수 있습니다. 이 그래프에서 최대 유량을 구하면 되고, Dinic’s Algorithm을 이용해 최대 유량을 구하면 100점을 받을 수 있습니다. 자세한 그래프 모델링은 아래 코드를 참고하세요.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="kt">int</span> <span class="n">SZ</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">GetRange</span><span class="p">(</span><span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">){</span> <span class="n">l</span> <span class="o">|=</span> <span class="n">SZ</span><span class="p">;</span> <span class="n">r</span> <span class="o">|=</span> <span class="n">SZ</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">res</span><span class="p">;</span> <span class="k">while</span><span class="p">(</span><span class="n">l</span> <span class="o">&lt;=</span> <span class="n">r</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">l</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="n">res</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">l</span><span class="o">++</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="o">~</span><span class="n">r</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="n">res</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">r</span><span class="o">--</span><span class="p">);</span> <span class="n">l</span> <span class="o">&gt;&gt;=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">r</span> <span class="o">&gt;&gt;=</span> <span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="n">res</span><span class="p">;</span> <span class="p">}</span> <span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="nc">FlowType</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">_Sz</span><span class="p">,</span> <span class="n">FlowType</span> <span class="n">_Inf</span><span class="o">=</span><span class="mi">1'000'000'007</span><span class="p">&gt;</span> <span class="k">struct</span> <span class="nc">Dinic</span><span class="p">{</span> <span class="k">struct</span> <span class="nc">Edge</span><span class="p">{</span> <span class="kt">int</span> <span class="n">v</span><span class="p">,</span> <span class="n">dual</span><span class="p">;</span> <span class="n">FlowType</span> <span class="n">c</span><span class="p">;</span> <span class="p">};</span> <span class="kt">int</span> <span class="n">Level</span><span class="p">[</span><span class="n">_Sz</span><span class="p">],</span> <span class="n">Work</span><span class="p">[</span><span class="n">_Sz</span><span class="p">],</span> <span class="n">N</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">Edge</span><span class="o">&gt;</span> <span class="n">G</span><span class="p">[</span><span class="n">_Sz</span><span class="p">];</span> <span class="kt">void</span> <span class="n">clear</span><span class="p">(){</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">_Sz</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">G</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">clear</span><span class="p">();</span> <span class="p">}</span> <span class="kt">void</span> <span class="n">AddEdge</span><span class="p">(</span><span class="kt">int</span> <span class="n">s</span><span class="p">,</span> <span class="kt">int</span> <span class="n">e</span><span class="p">,</span> <span class="n">FlowType</span> <span class="n">x</span><span class="p">){</span> <span class="n">G</span><span class="p">[</span><span class="n">s</span><span class="p">].</span><span class="n">push_back</span><span class="p">({</span><span class="n">e</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">G</span><span class="p">[</span><span class="n">e</span><span class="p">].</span><span class="n">size</span><span class="p">(),</span> <span class="n">x</span><span class="p">});</span> <span class="n">G</span><span class="p">[</span><span class="n">e</span><span class="p">].</span><span class="n">push_back</span><span class="p">({</span><span class="n">s</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">G</span><span class="p">[</span><span class="n">s</span><span class="p">].</span><span class="n">size</span><span class="p">()</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">});</span> <span class="p">}</span> <span class="kt">bool</span> <span class="n">BFS</span><span class="p">(</span><span class="kt">int</span> <span class="n">S</span><span class="p">,</span> <span class="kt">int</span> <span class="n">T</span><span class="p">){</span> <span class="n">memset</span><span class="p">(</span><span class="n">Level</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">Level</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">*</span> <span class="n">N</span><span class="p">);</span> <span class="n">queue</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">Q</span><span class="p">;</span> <span class="n">Q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">S</span><span class="p">);</span> <span class="n">Level</span><span class="p">[</span><span class="n">S</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">while</span><span class="p">(</span><span class="n">Q</span><span class="p">.</span><span class="n">size</span><span class="p">()){</span> <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">Q</span><span class="p">.</span><span class="n">front</span><span class="p">();</span> <span class="n">Q</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span> <span class="k">for</span><span class="p">(</span><span class="k">const</span> <span class="k">auto</span> <span class="o">&amp;</span><span class="n">i</span> <span class="o">:</span> <span class="n">G</span><span class="p">[</span><span class="n">v</span><span class="p">]){</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">Level</span><span class="p">[</span><span class="n">i</span><span class="p">.</span><span class="n">v</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="n">i</span><span class="p">.</span><span class="n">c</span><span class="p">)</span> <span class="n">Q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">i</span><span class="p">.</span><span class="n">v</span><span class="p">),</span> <span class="n">Level</span><span class="p">[</span><span class="n">i</span><span class="p">.</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">Level</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="k">return</span> <span class="n">Level</span><span class="p">[</span><span class="n">T</span><span class="p">];</span> <span class="p">}</span> <span class="n">FlowType</span> <span class="n">DFS</span><span class="p">(</span><span class="kt">int</span> <span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">T</span><span class="p">,</span> <span class="n">FlowType</span> <span class="n">tot</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">v</span> <span class="o">==</span> <span class="n">T</span><span class="p">)</span> <span class="k">return</span> <span class="n">tot</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="o">&amp;</span><span class="n">_i</span><span class="o">=</span><span class="n">Work</span><span class="p">[</span><span class="n">v</span><span class="p">];</span> <span class="n">_i</span><span class="o">&lt;</span><span class="n">G</span><span class="p">[</span><span class="n">v</span><span class="p">].</span><span class="n">size</span><span class="p">();</span> <span class="n">_i</span><span class="o">++</span><span class="p">){</span> <span class="n">Edge</span> <span class="o">&amp;</span><span class="n">i</span> <span class="o">=</span> <span class="n">G</span><span class="p">[</span><span class="n">v</span><span class="p">][</span><span class="n">_i</span><span class="p">];</span> <span class="k">if</span><span class="p">(</span><span class="n">Level</span><span class="p">[</span><span class="n">i</span><span class="p">.</span><span class="n">v</span><span class="p">]</span> <span class="o">!=</span> <span class="n">Level</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">||</span> <span class="o">!</span><span class="n">i</span><span class="p">.</span><span class="n">c</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span> <span class="n">FlowType</span> <span class="n">fl</span> <span class="o">=</span> <span class="n">DFS</span><span class="p">(</span><span class="n">i</span><span class="p">.</span><span class="n">v</span><span class="p">,</span> <span class="n">T</span><span class="p">,</span> <span class="n">min</span><span class="p">(</span><span class="n">tot</span><span class="p">,</span> <span class="n">i</span><span class="p">.</span><span class="n">c</span><span class="p">));</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">fl</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span> <span class="n">i</span><span class="p">.</span><span class="n">c</span> <span class="o">-=</span> <span class="n">fl</span><span class="p">;</span> <span class="n">G</span><span class="p">[</span><span class="n">i</span><span class="p">.</span><span class="n">v</span><span class="p">][</span><span class="n">i</span><span class="p">.</span><span class="n">dual</span><span class="p">].</span><span class="n">c</span> <span class="o">+=</span> <span class="n">fl</span><span class="p">;</span> <span class="k">return</span> <span class="n">fl</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="n">FlowType</span> <span class="n">MaxFlow</span><span class="p">(</span><span class="kt">int</span> <span class="n">_N</span><span class="p">,</span> <span class="kt">int</span> <span class="n">S</span><span class="p">,</span> <span class="kt">int</span> <span class="n">T</span><span class="p">){</span> <span class="n">FlowType</span> <span class="n">ret</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">tmp</span><span class="p">;</span> <span class="n">N</span> <span class="o">=</span> <span class="n">_N</span><span class="p">;</span> <span class="k">while</span><span class="p">(</span><span class="n">BFS</span><span class="p">(</span><span class="n">S</span><span class="p">,</span> <span class="n">T</span><span class="p">)){</span> <span class="n">memset</span><span class="p">(</span><span class="n">Work</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">Work</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">*</span> <span class="n">N</span><span class="p">);</span> <span class="k">while</span><span class="p">((</span><span class="n">tmp</span> <span class="o">=</span> <span class="n">DFS</span><span class="p">(</span><span class="n">S</span><span class="p">,</span> <span class="n">T</span><span class="p">,</span> <span class="n">_Inf</span><span class="p">)))</span> <span class="n">ret</span> <span class="o">+=</span> <span class="n">tmp</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> <span class="p">}</span> <span class="p">};</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">C</span><span class="p">;</span> <span class="n">string</span> <span class="n">S</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">V</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span> <span class="n">Dinic</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="p">(</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="mi">20</span><span class="p">)</span><span class="o">+</span><span class="mi">303030</span><span class="o">&gt;</span> <span class="n">Flow</span><span class="p">;</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">S</span><span class="p">;</span> <span class="n">N</span> <span class="o">=</span> <span class="n">S</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">V</span><span class="p">[</span><span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">-</span><span class="sc">'A'</span><span class="p">].</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">3</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="k">if</span><span class="p">(</span><span class="n">i</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="o">&amp;</span><span class="n">j</span> <span class="o">:</span> <span class="n">V</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="n">j</span><span class="p">.</span><span class="n">second</span> <span class="o">=</span> <span class="n">C</span><span class="o">++</span><span class="p">;</span> <span class="k">while</span><span class="p">(</span><span class="n">SZ</span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">size</span><span class="p">()</span> <span class="o">+</span> <span class="n">V</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">size</span><span class="p">())</span> <span class="n">SZ</span> <span class="o">&lt;&lt;=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// 1 ~ 2S-1 : segment tree</span> <span class="c1">// 2S ~ 2S+B-1 : B</span> <span class="c1">// 0, 2S+B : S, T</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">src</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">snk</span> <span class="o">=</span> <span class="mi">2</span><span class="o">*</span><span class="n">SZ</span> <span class="o">+</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">size</span><span class="p">();</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">SZ</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">Flow</span><span class="p">.</span><span class="n">AddEdge</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">i</span><span class="o">&lt;&lt;</span><span class="mi">1</span><span class="p">,</span> <span class="mf">1e9</span><span class="p">),</span> <span class="n">Flow</span><span class="p">.</span><span class="n">AddEdge</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">i</span><span class="o">&lt;&lt;</span><span class="mi">1</span><span class="o">|</span><span class="mi">1</span><span class="p">,</span> <span class="mf">1e9</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">V</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">size</span><span class="p">()</span><span class="o">+</span><span class="n">V</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">Flow</span><span class="p">.</span><span class="n">AddEdge</span><span class="p">(</span><span class="n">i</span><span class="o">|</span><span class="n">SZ</span><span class="p">,</span> <span class="n">snk</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="n">Flow</span><span class="p">.</span><span class="n">AddEdge</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="mi">2</span><span class="o">*</span><span class="n">SZ</span><span class="o">+</span><span class="n">i</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="k">auto</span> <span class="n">it1</span> <span class="o">=</span> <span class="n">upper_bound</span><span class="p">(</span><span class="n">V</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">begin</span><span class="p">(),</span> <span class="n">V</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">end</span><span class="p">(),</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">i</span><span class="p">]);</span> <span class="k">if</span><span class="p">(</span><span class="n">it1</span> <span class="o">!=</span> <span class="n">V</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">begin</span><span class="p">()){</span> <span class="k">for</span><span class="p">(</span><span class="k">const</span> <span class="k">auto</span> <span class="o">&amp;</span><span class="n">j</span> <span class="o">:</span> <span class="n">GetRange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">prev</span><span class="p">(</span><span class="n">it1</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">second</span><span class="p">))</span> <span class="n">Flow</span><span class="p">.</span><span class="n">AddEdge</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">SZ</span><span class="o">+</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="mf">1e9</span><span class="p">);</span> <span class="p">}</span> <span class="k">auto</span> <span class="n">it2</span> <span class="o">=</span> <span class="n">upper_bound</span><span class="p">(</span><span class="n">V</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">begin</span><span class="p">(),</span> <span class="n">V</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">end</span><span class="p">(),</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">i</span><span class="p">]);</span> <span class="k">if</span><span class="p">(</span><span class="n">it2</span> <span class="o">!=</span> <span class="n">V</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">end</span><span class="p">()){</span> <span class="k">for</span><span class="p">(</span><span class="k">const</span> <span class="k">auto</span> <span class="o">&amp;</span><span class="n">j</span> <span class="o">:</span> <span class="n">GetRange</span><span class="p">(</span><span class="n">it2</span><span class="o">-&gt;</span><span class="n">second</span><span class="p">,</span> <span class="n">V</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">back</span><span class="p">().</span><span class="n">second</span><span class="p">))</span> <span class="n">Flow</span><span class="p">.</span><span class="n">AddEdge</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">SZ</span><span class="o">+</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="mf">1e9</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">Flow</span><span class="p">.</span><span class="n">MaxFlow</span><span class="p">(</span><span class="n">snk</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">src</span><span class="p">,</span> <span class="n">snk</span><span class="p">);</span> <span class="p">}</span> </code></pre></div></div> <h3 id="2-3-보급">2-3. 보급</h3> <p>그래프를 명시적으로 만들고 위상 정렬을 하는 것은 그래프의 간선 개수가 $O(N^2)$이기 때문에, 여기에서 더 발전하는 것은 힘들어 보입니다. 다른 풀이를 생각해야 합니다.</p> <p>$i \neq j, X_i &lt; X_j, Y_i &lt; Y_j$인 순서쌍 $(i, j)$을 고려해야 합니다. 3개나 되는 조건을 모두 고려하는 것은 복잡하므로, $X$ 기준으로 정렬해서 2개의 조건 $i &lt; j, Y_i &lt; Y_j$만 고려해도 되도록 만듭시다.</p> <p>$i &lt; j, Y_i &lt; Y_j$인 순서쌍 $(i, j)$에 대해 $V_i &lt; V_j$를 만족해야 하므로, $B_i &lt; V_j \leq B_j, A_i \leq V_i &lt; A_j$라고 생각해도 됩니다.<br />조건을 만족하는 모든 순서쌍 $(i,j)$에 대해, $A_j \leftarrow \max\lbrace A_j, A_i + 1 \rbrace$, $B_i \leftarrow \min\lbrace B_i, B_j + 1\rbrace$를 수행합시다. $A$를 계산할 때는 $j$ 오름차순으로, $B$를 계산할 때는 $i$ 내림차순으로 계산하면 됩니다. 이 과정은 세그먼트 트리의 인덱스로 $Y$ 좌표를 사용하는 것으로 $O(N \log N)$에 수행할 수 있습니다.</p> <p>이제 새로 수정한 $A, B$를 이용해 $A_i \leq V_i \leq B_i$를 만족하는 $V_i$를 구하는 일만 남았습니다. 이 작업은 회의실 배정 문제처럼 $B$가 작은 기지부터 배정하면 되고, 우선순위 큐를 이용해 $O(N \log N)$에 할 수 있습니다.</p> <p>여담으로, 2018 KAIST ACM-ICPC Mock Competition의 B번 문제로 출제된 <a href="https://www.acmicpc.net/problem/16182">Dumae</a> 문제와 매우 유사합니다. Dumae 문제는 입력으로 DAG가 직접 주어지기 때문에 더 쉽게 해결할 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="k">struct</span> <span class="nc">Point</span><span class="p">{</span> <span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">i</span><span class="p">;</span> <span class="n">Point</span><span class="p">()</span> <span class="o">=</span> <span class="k">default</span><span class="p">;</span> <span class="k">friend</span> <span class="n">istream</span><span class="o">&amp;</span> <span class="k">operator</span> <span class="o">&gt;&gt;</span> <span class="p">(</span><span class="n">istream</span> <span class="o">&amp;</span><span class="n">in</span><span class="p">,</span> <span class="n">Point</span> <span class="o">&amp;</span><span class="n">p</span><span class="p">){</span> <span class="k">return</span> <span class="n">in</span> <span class="o">&gt;&gt;</span> <span class="n">p</span><span class="p">.</span><span class="n">x</span> <span class="o">&gt;&gt;</span> <span class="n">p</span><span class="p">.</span><span class="n">y</span> <span class="o">&gt;&gt;</span> <span class="n">p</span><span class="p">.</span><span class="n">a</span> <span class="o">&gt;&gt;</span> <span class="n">p</span><span class="p">.</span><span class="n">b</span><span class="p">;</span> <span class="p">}</span> <span class="kt">bool</span> <span class="k">operator</span> <span class="o">&gt;</span> <span class="p">(</span><span class="k">const</span> <span class="n">Point</span> <span class="o">&amp;</span><span class="n">p</span><span class="p">){</span> <span class="k">return</span> <span class="n">b</span> <span class="o">&gt;</span> <span class="n">p</span><span class="p">.</span><span class="n">b</span><span class="p">;</span> <span class="p">}</span> <span class="c1">// comparator for min heap</span> <span class="p">};</span> <span class="k">struct</span> <span class="nc">SegmentTree</span><span class="p">{</span> <span class="k">static</span> <span class="k">constexpr</span> <span class="kt">int</span> <span class="n">SZ</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="mi">18</span><span class="p">;</span> <span class="kt">int</span> <span class="n">T</span><span class="p">[</span><span class="n">SZ</span> <span class="o">&lt;&lt;</span> <span class="mi">1</span><span class="p">];</span> <span class="n">function</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span><span class="kt">int</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">merge</span><span class="p">;</span> <span class="kt">void</span> <span class="n">init</span><span class="p">(</span><span class="kt">int</span> <span class="n">id</span><span class="p">,</span> <span class="n">function</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span><span class="kt">int</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">func</span><span class="p">){</span> <span class="n">fill</span><span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="n">T</span><span class="o">+</span><span class="n">SZ</span><span class="o">*</span><span class="mi">2</span><span class="p">,</span> <span class="n">id</span><span class="p">);</span> <span class="n">merge</span> <span class="o">=</span> <span class="n">func</span><span class="p">;</span> <span class="p">}</span> <span class="kt">void</span> <span class="n">update</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">v</span><span class="p">){</span> <span class="n">x</span> <span class="o">|=</span> <span class="n">SZ</span><span class="p">;</span> <span class="n">T</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">merge</span><span class="p">(</span><span class="n">T</span><span class="p">[</span><span class="n">x</span><span class="p">],</span> <span class="n">v</span><span class="p">);</span> <span class="k">while</span><span class="p">(</span><span class="n">x</span> <span class="o">&gt;&gt;=</span> <span class="mi">1</span><span class="p">)</span> <span class="n">T</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">merge</span><span class="p">(</span><span class="n">T</span><span class="p">[</span><span class="n">x</span><span class="o">&lt;&lt;</span><span class="mi">1</span><span class="p">],</span> <span class="n">T</span><span class="p">[</span><span class="n">x</span><span class="o">&lt;&lt;</span><span class="mi">1</span><span class="o">|</span><span class="mi">1</span><span class="p">]);</span> <span class="p">}</span> <span class="kt">int</span> <span class="n">query</span><span class="p">(</span><span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">){</span> <span class="n">l</span> <span class="o">|=</span> <span class="n">SZ</span><span class="p">;</span> <span class="n">r</span> <span class="o">|=</span> <span class="n">SZ</span><span class="p">;</span> <span class="kt">int</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">T</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> <span class="k">while</span><span class="p">(</span><span class="n">l</span> <span class="o">&lt;=</span> <span class="n">r</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">l</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">merge</span><span class="p">(</span><span class="n">ret</span><span class="p">,</span> <span class="n">T</span><span class="p">[</span><span class="n">l</span><span class="o">++</span><span class="p">]);</span> <span class="k">if</span><span class="p">(</span><span class="o">~</span><span class="n">r</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">merge</span><span class="p">(</span><span class="n">ret</span><span class="p">,</span> <span class="n">T</span><span class="p">[</span><span class="n">r</span><span class="o">--</span><span class="p">]);</span> <span class="n">l</span> <span class="o">&gt;&gt;=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">r</span> <span class="o">&gt;&gt;=</span> <span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="n">Tmn</span><span class="p">,</span> <span class="n">Tmx</span><span class="p">;</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">R</span><span class="p">[</span><span class="mi">252525</span><span class="p">];</span> <span class="n">Point</span> <span class="n">A</span><span class="p">[</span><span class="mi">252525</span><span class="p">];</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">i</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span> <span class="n">sort</span><span class="p">(</span><span class="n">A</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">A</span><span class="o">+</span><span class="n">N</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="p">[](</span><span class="k">auto</span> <span class="n">u</span><span class="p">,</span> <span class="k">auto</span> <span class="n">v</span><span class="p">){</span> <span class="k">return</span> <span class="n">u</span><span class="p">.</span><span class="n">x</span> <span class="o">&lt;</span> <span class="n">v</span><span class="p">.</span><span class="n">x</span><span class="p">;</span> <span class="p">});</span> <span class="n">Tmn</span><span class="p">.</span><span class="n">init</span><span class="p">(</span><span class="n">N</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="p">[](</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">int</span> <span class="p">{</span> <span class="k">return</span> <span class="n">min</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span> <span class="p">});</span> <span class="n">Tmx</span><span class="p">.</span><span class="n">init</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="p">[](</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">int</span> <span class="p">{</span> <span class="k">return</span> <span class="n">max</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span> <span class="p">});</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">a</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">a</span><span class="p">,</span> <span class="n">Tmx</span><span class="p">.</span><span class="n">query</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">y</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span> <span class="n">Tmx</span><span class="p">.</span><span class="n">update</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">y</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">a</span><span class="p">);</span> <span class="p">}</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">&gt;=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">--</span><span class="p">){</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">b</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">b</span><span class="p">,</span> <span class="n">Tmn</span><span class="p">.</span><span class="n">query</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">y</span><span class="p">,</span> <span class="n">N</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span> <span class="n">Tmn</span><span class="p">.</span><span class="n">update</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">y</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">b</span><span class="p">);</span> <span class="p">}</span> <span class="n">sort</span><span class="p">(</span><span class="n">A</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">A</span><span class="o">+</span><span class="n">N</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="p">[](</span><span class="k">auto</span> <span class="n">u</span><span class="p">,</span> <span class="k">auto</span> <span class="n">v</span><span class="p">){</span> <span class="k">return</span> <span class="n">u</span><span class="p">.</span><span class="n">a</span> <span class="o">&lt;</span> <span class="n">v</span><span class="p">.</span><span class="n">a</span><span class="p">;</span> <span class="p">});</span> <span class="n">priority_queue</span><span class="o">&lt;</span><span class="n">Point</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">Point</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">greater</span><span class="o">&lt;&gt;&gt;</span> <span class="n">Q</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">j</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">while</span><span class="p">(</span><span class="n">j</span> <span class="o">&lt;=</span> <span class="n">N</span> <span class="o">&amp;&amp;</span> <span class="n">A</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">a</span> <span class="o">&lt;=</span> <span class="n">i</span><span class="p">)</span> <span class="n">Q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">j</span><span class="o">++</span><span class="p">]);</span> <span class="k">if</span><span class="p">(</span><span class="n">Q</span><span class="p">.</span><span class="n">empty</span><span class="p">()){</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"NO"</span><span class="p">;</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="k">auto</span> <span class="n">p</span> <span class="o">=</span> <span class="n">Q</span><span class="p">.</span><span class="n">top</span><span class="p">();</span> <span class="n">Q</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span> <span class="k">if</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">a</span> <span class="o">&lt;=</span> <span class="n">i</span> <span class="o">&amp;&amp;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">p</span><span class="p">.</span><span class="n">b</span><span class="p">)</span> <span class="n">R</span><span class="p">[</span><span class="n">p</span><span class="p">.</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span> <span class="k">else</span><span class="p">{</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"NO"</span><span class="p">;</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"YES</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">R</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div>JusticeHui총평 및 문제 감상백준18349 천지창조2022-05-01T23:59:00+00:002022-05-01T23:59:00+00:00https://justicehui.github.io/ps/2022/05/01/BOJ18349<h3 id="문제-링크">문제 링크</h3> <ul> <li>http://icpc.me/18349</li> </ul> <h3 id="풀이">풀이</h3> <p>문제를 천천히 읽어보면 문제를 풀기 위해 필요한 작업은 쉽게 알 수 있고, 이 작업들을 효율적으로 처리하는 것이 문제의 핵심입니다. 구체적으로, 다음과 같은 작업을 빠르게 수행해야 합니다. 각각의 개념을 모두 설명하는 것은 너무 어렵기 때문에, 문자열 파트를 제외한 다른 부분은 필요한 알고리즘과 설명 링크로 대신하겠습니다.</p> <ul> <li>Voronoi Diagram</li> <li>Minimum Spanning Tree</li> <li>Path Maximum Query on Dynamic Tree</li> <li>Nearest Point Search</li> <li>Longest Common Substring Query (Offline)</li> </ul> <p>보로노이 다이어그램은 Fortune’s Algorithm을 이용해 $O(N \log N)$에 구할 수 있습니다. (<a href="https://jacquesheunis.com/post/fortunes-algorithm/">설명</a>, <a href="https://github.com/zigui-ps/VoronoiDiagram/blob/master/teamnote_VoronoiDiagram.cpp">코드</a>)<br />보로노이 다이어그램의 듀얼 그래프는 들로네 삼각분할이므로 $O(N \log N)$에 들로네 삼각분할을 구해도 됩니다.</p> <p>이 문제에서 최소 스패닝 트리를 만들 때, 한 정점에서 시작해 트리 하나를 유지하는 방식으로 만들기 때문에 Prim’s Algorithm을 사용해야 합니다. 들로네 삼각분할(평면 그래프) 상의 간선만 사용하기 때문에 $O(N \log N)$에 구할 수 있습니다.</p> <p>다이나믹 트리에서 경로의 최댓값은 링크컷 트리를 이용해 amortized $O(\log N)$에 구할 수 있습니다. (<a href="https://justicehui.github.io/hard-algorithm/2021/01/01/link-cut-tree/">설명&amp;코드</a>)</p> <p>가장 가까운 점을 찾는 것은 보로노이 다이어그램에서 스위핑을 해도 되고, k-d tree를 사용해도 됩니다. (<a href="https://algoshitpo.github.io/2020/02/09/kdtree/">설명&amp;코드</a>)<br />평면을 쪼갤 때 반평면으로 쪼개면 주어진 점의 좌표가 작고 쿼리로 주어지는 점의 좌표가 클 때 시간 초과가 발생합니다. 반평면이 아닌 직사각형으로 쪼개야 시간 초과를 피할 수 있습니다. (thanks to @jh05013)</p> <h4 id="문자열-최장-공통-부분-문자열-쿼리">문자열 (최장 공통 부분 문자열 쿼리)</h4> <p>일반적으로 두 문자열 $S, T$의 최장 공통 부분 문자열을 찾는 것은 $S+T$의 LCP 배열을 구한 다음, $T$의 모든 접미사에 대해 LCP 배열 상에서 가장 가까운 $S$의 접미사까지의 구간 최댓값을 구하면 됩니다. 투포인터를 이용하면 $O(\vert S\vert + \vert T\vert)$ 시간에 구할 수 있습니다.<br />고정된 $S$에 대해 $T_i$와의 최장 공통 부분 문자열을 찾는 것도 $S+T_1+T_2+\cdots+T_k$에서 비슷한 방식으로 할 수 있습니다. LCP 배열을 구하는데 $O(\vert S\vert + \sum \vert T_i\vert)$, 쿼리는 각각 $O(\vert S\vert +\vert T_i\vert)$에 처리할 수 있으므로 전체 시간 복잡도는 $O(k\vert S\vert + \sum \vert T_i\vert)$입니다.</p> <p>만약 $\vert S_i\vert &lt; \vert S_j\vert$일 때 쿼리를 $O(\vert S_i\vert)$에 처리할 수 있다면, 문제에서 요구하는 $Q$개의 쿼리를 $O((Q+S)\sqrt S)$에 모두 처리할 수 있습니다. 이때 $S = \sum\vert S_i\vert$입니다.</p> <p>먼저, $S_1+S_2+\cdots+S_n$의 LCP 배열을 $O(S)$에 구합시다. 세 가지 경우로 나눠서 처리합니다.</p> <ol> <li>$\vert S_i\vert,\ \vert S_j\vert \leq \sqrt S$ <ul> <li>투포인터를 이용해 각 쿼리를 $O(\vert S_i\vert+\vert S_j\vert)$에 처리할 수 있습니다. 이 케이스는 최대 $Q$번 발생하고, $\vert S_i\vert,\ \vert S_j\vert \leq \sqrt S$이므로 전체 시간 복잡도는 $O(Q\sqrt S)$입니다.</li> </ul> </li> <li>$\vert S_i\vert \leq \sqrt S,\ \vert S_j\vert &gt; \sqrt S$ <ul> <li>길이가 $\sqrt S$보다 긴 문자열은 최대 $\sqrt S$개 존재합니다. 그러므로 접미사 배열에서 $S_j$의 접미사의 위치를 모았을 때, 임의의 지점에서의 lower bound를 $O(S\sqrt S)$에 모두 전처리할 수 있습니다.</li> <li>전처리된 lower bound를 이용하면 쿼리를 $O(\vert S_i\vert)$에 처리할 수 있고, $\vert S_i\vert \leq \sqrt S$이므로 전체 시간 복잡도는 $O(Q\sqrt S)$입니다.</li> </ul> </li> <li>$\vert S_i\vert,\ \vert S_j\vert &gt; \sqrt S$ <ul> <li>(2)에서 전처리된 배열을 사용하면 쿼리를 $O(\vert S_i\vert)$에 처리할 수 있습니다.</li> <li>길이가 $\sqrt S$보다 긴 문자열은 최대 $\sqrt S$개 존재하므로, 서로 다른 $(i, j)$ 순서쌍은 최대 $(\sqrt S)^2 = S$개 존재합니다. 전체 시간 복잡도는 $O(S\sqrt S)$입니다.</li> <li>쿼리 결과를 캐싱해야 합니다.</li> </ul> </li> </ol> <p>접미사 배열과 LCP 배열을 선형 시간에 구하고, 구간 최댓값 쿼리를 선형 시간 전처리 + 상수 시간에 처리하면 $O(Q+S\sqrt S)$에 모든 쿼리를 처리할 수 있습니다.</p> <p>Suffix Automaton을 사용해도 동일한 시간 복잡도로 쿼리를 처리할 수 있습니다. ($S$의 suffix automaton을 만드는데 $O(\vert S\vert)$가 걸리고, $T$와의 최장 공통 부분 문자열을 구하는데 $O(\vert T\vert)$가 걸립니다.)</p> <p>설명 링크 모음</p> <ul> <li>선형 시간 접미사 배열 (<a href="http://www.secmem.org/blog/2021/11/21/linear-suffix-array/">설명</a>, <a href="https://github.com/koosaga/olympiad/blob/master/Library/codes/string/suffix_array.cpp">코드</a>)</li> <li>선형 시간 전처리, 상수 시간 RMQ (<a href="https://codeforces.com/blog/entry/78931">설명&amp;코드</a>)</li> <li>Suffix Automaton (<a href="https://github.com/joy-mollick/Suffix-automata-Problems/blob/master/Longest%20Common%20Substring%20of%20Two%20Strings.cpp">코드</a>)</li> </ul>JusticeHui문제 링크 http://icpc.me/183492021년 국제정보올림피아드 선발고사 풀이2022-04-16T06:46:00+00:002022-04-16T06:46:00+00:00https://justicehui.github.io/koi/2022/04/16/2021tst<p>1차 2번(통신망), 2차 1번(총 쏘기), 2차 4번(가로등)은 아직 풀이가 준비되지 않았습니다.<br />풀이가 준비되지 않은 세 문제는 모두 Petrozavodsk Programming Camp Winter 2022에 사용되었으며, 영어로 된 만점 풀이는 <a href="https://codeforces.com/gym/103627/attachments/download/15719/gp20220202sol.pdf">캠프 에디토리얼</a>에서 확인할 수 있습니다. 통신망은 Critical Vertex, 총 쏘기는 Two Bullets, 가로등은 Streetlights입니다.</p> <h2 id="1-1-카드-뒤집기-게임-백준-22026">1-1. 카드 뒤집기 게임 (백준 22026)</h2> <h4 id="subtask-3-m-leq-n-leq-1000-100점">Subtask 3. $M \leq N \leq 1\,000$ (100점)</h4> <p>$0\cdots M-1$번째 행과 $0\cdots M-1$번째 열을 모두 카드에 그려진 패턴과 동일하게 만드는 방법은 유일합니다. 그러므로 $0\cdots M-1$번째 행과 열을 그리디하게 뒤집어서 카드에 그려진 패턴대로 만든 다음, 전체 격자의 카드와 패턴이 동일한지 확인하면 됩니다.<br />시간 복잡도는 $O(NM)$입니다.</p> <h2 id="1-2-통신망-백준-22027">1-2. 통신망 (백준 22027)</h2> <p>풀이 준비 중</p> <h2 id="1-3-렉-백준-22028">1-3. 렉 (백준 22028)</h2> <h4 id="subtask-2-m--0-16점">Subtask 2. $M = 0$ (16점)</h4> <p>각 직사각형 $[x_1,x_2]\times[y_1,y_2]$에 대해 $(x_1,y_1), (x_2+1,y_2+1)$에 1을 더하고 $(x_2+1,y_1), (x_1,y_2+1)$에 -1을 더한 뒤 2차원 누적합을 구하면, $(x,y)$의 정답이 $(x,y)$에 저장됩니다. $x$좌표 순서대로 스위핑하면서 펜윅 트리를 이용해 $y$축의 누적합을 관리하면 $O((N+Q) \log X)$에 문제를 해결할 수 있습니다.</p> <h4 id="subtask-4-상하좌우-이동-29점">Subtask 4. 상하좌우 이동 (29점)</h4> <p>직사각형이 위로 이동하는 것만 생각해 봅시다. 구체적으로, $[x_1,x_2]\times[y_1,y_2]$가 $y$좌표가 증가하는 방향으로 $d$만큼 이동하는 상황을 가정하겠습니다.</p> <p>Subtask 2처럼 2차원 누적합의 관점에서 생각하면, 위로 올라가는 것은 $(x_1,y_1+1\cdots y_1+d)$와 $(x_2+1,y_2+2\cdots y_2+d+1)$에 1을 더하고, $(x_2+1,y_1+1\cdots y_1+d)$와 $(x_1, y_2+2\cdots y_2+d+1)$에 -1을 더하는 것과 동일합니다. Subtask 2와 마찬가지로 $x$좌표 순서대로 스위핑을 하면서 $y$축의 누적합을 관리할 것입니다.<br />구간 $[s,e]$에 1을 더하고 누적합을 구하는 것은 $s, s+1, \cdots, e$에 $1, 2, \cdots, e-s+1$을 더하고, $e+1$ 이상인 지점에는 $e-s+1$을 더하는 것이라고 생각할 수 있습니다. 즉, 구간에 일차 함수를 더하는 것과 특정 값을 더하는 것으로 나눠서 생각할 수 있습니다. 펜윅 트리 2개를 이용해 할 수 있습니다.</p> <p>아래로 이동하는 것은 뒤집어서 처리하면 되고, 좌우로 이동하는 것은 $x, y$좌표를 바꿔서 처리하면 됩니다. $O((N+M+Q)\log X)$에 해결할 수 있습니다.</p> <h4 id="subtask-6-100점">Subtask 6. (100점)</h4> <p>$y=x$ 직선에 평행하게 이동하는 상황에서 $[1,Q_x]\times [1,Q_y]$ 영역의 합을 구하는 것은, 해당 영역에 포함되는 기울기가 1인 일차 함수들의 길이를 모두 더한 것이라고 생각할 수 있습니다. $x-y &gt; Q_x-Q_y \textit{ and } x \leq Q_x$인 삼각형 영역(오른쪽 아래)과 $ x-y \leq Q_x-Q_y \textit{ and } y \leq Q_y$인 삼각형 영역(왼쪽 위)으로 나눠서 생각합시다.<br />$(x,y)$를 $(y-x,x)$로 변환하면 원래 <strong>오른쪽 아래 영역</strong>에 있던 점이 모두 점 $Q$의 왼쪽 아래로 이동합니다. 마찬가지로 $(x,y)$를 $(x-y,y)$로 변환하면 <strong>왼쪽 위 영역</strong>에 있던 점이 모두 점 $Q$의 왼쪽 아래로 이동합니다. 각각 $y-x$와 $x-y$ 순서대로 스위핑하면 Subtask 4와 동일한 방법으로 처리할 수 있습니다.<br />좌표 변환 과정은 아래 텍스트에서 <code class="language-plaintext highlighter-rouge">I</code>에 주목해보세요.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GHI (x-y,y) GHI (y-x,x) CFI DEF &lt;--------- DEF --------&gt; BEH ABC ABC ADG </code></pre></div></div> <p>$y=-x$ 직선에 평행하게 이동하는 것도 비슷하게 처리할 수 있습니다. $x+y \leq Q_x+Q_y \textit{ and }y\leq Q_y$인 사다리꼴 영역에서 $x+y\leq Q_x+Q_y \textit{ and } x &gt; Q_x$인 삼각형 영역을 빼면 됩니다.<br />$(x,y)$를 $(x+y,y)$로 변환하면 <strong>사다리꼴 영역</strong>에 있던 점이 모두 점 $Q$의 왼쪽 아래로 이동하고, $(x+y,-x)$로 변환하면 <strong>삼각형 영역</strong>에 있던 점이 모두 $Q$의 왼쪽 아래로 이동합니다. 각각 $x+y$ 순서대로 스위핑하면 Subtask 4와 동일한 방법으로 처리할 수 있습니다.<br />좌표 변환 과정은 아래 텍스트에서 <code class="language-plaintext highlighter-rouge">13</code>에 주목해보세요.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 1 2 3 4 5 1 2 3 4 5 21 16 11 6 1 6 7 8 9 10 (x+y,y) 6 7 8 9 10 (x+y,-y) 22 17 12 7 2 11 12 13 14 15 &lt;-------- 11 12 13 14 15 ----------&gt; 23 18 13 8 3 16 17 18 19 20 16 17 18 19 20 24 19 14 9 4 21 22 23 24 25 21 22 23 24 25 25 20 15 10 5 </code></pre></div></div> <p>전체 시간 복잡도는 $O((N+M+Q)\log N)$입니다.</p> <h2 id="1-4-철도-백준-22029">1-4. 철도 (백준 22029)</h2> <h4 id="subtask-2-k--1-17점">Subtask 2. $K = 1$ (17점)</h4> <p>트리에 간선을 하나 추가하면 사이클이 정확히 한 개 존재하는 그래프가 됩니다. 이렇게 만들어진 사이클과 추가된 가짜 간선을 빠르게 찾을 수 있어야 합니다.</p> <p>사이클의 크기가 작을수록 고려해야 할 경우의 수가 적어지니까, 거리가 2인 두 정점을 가짜 간선으로 연결해서 크기가 3인 사이클을 만들어 봅시다. 가짜 간선으로 연결되지 않은 정점을 표시하면, 사이클에 속한 정점 중 표시되지 않은 두 정점을 연결한 간선이 가짜 간선입니다.<br />$N \leq 200$이므로 인접 행렬을 만든 다음 $O(N^3)$에 크기 3 사이클을 찾아도 충분합니다.</p> <h4 id="subtask-4-지름-leq-n2-46점">Subtask 4. 지름 $\leq N/2$ (46점)</h4> <p>정점 하나를 표시하는 것은 그 정점을 루트로 잡는 것이라고 생각할 수 있습니다. 트리에서 루트가 고정되어 있다면 DFS/BFS와 같은 그래프 순회를 통해 정점들의 순서를 붙일 수 있습니다.<br />특히 BFS를 이용하면 루트에서 각 정점 $v$까지 가는 거리 $D(v)$를 구할 수 있고, 일반적인 그래프에서 BFS 스패닝 트리에 속한 간선 $(u, v)$는 $\vert D(u) - D(v) \vert = 1$을 만족합니다. 즉, 아무 정점을 루트로 잡아서 BFS를 한 다음, 루트까지의 거리가 같은 정점들을 가짜 간선으로 연결하면 됩니다.</p> <p>이 풀이를 제출하면 100점을 받아야 할 것 같지만 46점이 나옵니다. 왜 그런지는 Subtask 5 풀이에서 살펴봅시다.</p> <h4 id="subtask-5-n-leq-500-100점">Subtask 5. $N \leq 500$ (100점)</h4> <p>트리가 선형이고 루트를 끝에 있는 정점으로 잡으면 거리가 같은 정점이 존재하지 않기 때문에 문제를 해결할 수 없습니다. 반대로 말하면, 거리가 같은 정점쌍이 $\lfloor N/2\rfloor-1$개 이상 존재하도록 만드는 루트를 찾으면 됩니다.</p> <p>여기까지 왔다면 다들 알겠지만 트리의 깊이를 $N/2$ 이하로 만들면 되고, 이는 지름의 중점이나 센트로이드를 루트로 잡으면 됩니다. 트리의 지름을 찾는 것과 센트로이드를 찾는 것 모두 선형 시간에 할 수 있기 때문에 $O(N)$에 문제를 해결할 수 있습니다.<br />사실 $N$의 크기가 작아서 모든 정점에 대해 시도해서 가짜 간선을 $K$개 만들 수 있는지 확인해도 됩니다.</p> <h2 id="2-1-총-쏘기-백준-22030">2-1. 총 쏘기 (백준 22030)</h2> <p>풀이 준비 중</p> <h2 id="2-2-회의실-백준-22031">2-2. 회의실 (백준 22031)</h2> <h4 id="subtask-2-k--1-17점-1">Subtask 2. $K = 1$ (17점)</h4> <p>Interval Graph가 주어졌을 때, 선분을 몇 개 제거해서 모든 컴포넌트의 크기가 $K$ 이하가 되도록 만드는 문제입니다. 이때 제거하는 선분의 가중치의 합을 최소화해야 합니다.</p> <p>$K = 1$이면 가중치가 있는 회의실 배정 문제이고, 끝점 기준으로 정렬한 뒤 DP를 하면 $O(N\log N)$에 해결할 수 있습니다. 회의실 배정 문제를 푼 다음, 전체 가중치 합에서 뺀 값을 출력하면 됩니다.</p> <h4 id="subtask-4-n-leq-250-53점">Subtask 4. $N \leq 250$ (53점)</h4> <p>끝점이 $i$ 이하인 선분들만 사용해서 만들 수 있는 가중치의 최댓값을 $D(i)$라고 정의합시다. 좌표 압축을 이용해 $i$의 범위를 $2N$으로 만들 수 있습니다.</p> <p>끝점이 $i$ 이하인 선분들만 사용하는 것은 $j &lt; i$인 $j$에 대해 $D(j)$를 구한 뒤, $(j, i]$ 구간에 완전히 포함되는 선분을 최대 $K$개 선책하는 것이라고 생각할 수 있습니다. 그러므로 $C(a,b)$를 $[a,b]$ 구간에 완전히 포함되는 최대 $K$개의 선분의 가중치 합이라고 정의하면 $D(i) = \max D_j + C(j+1,i)$입니다.<br />$C$ 배열은 $O(N^3)$에 모두 만들 수 있고 점화식은 $O(N^2)$에 계산할 수 있으므로 전체 시간 복잡도는 $O(N^3)$입니다.</p> <h4 id="subtask-5-n-leq-2500-150점">Subtask 5. $N \leq 2\,500$ (150점)</h4> <p>점화식을 계산하는 것 자체는 이미 $O(N^2)$으로 충분히 빠르기 때문에, $C$를 전처리하는 과정을 최적화해야 합니다. $i$를 고정하고 $j$를 증가시키면서 $C(i, j)$를 구할 때, 선분이 추가되는 상황에서 가장 큰 $K$개를 관리하는 것은 최소 힙을 이용해 수행할 수 있습니다. 즉, $C(i,\ast)$를 계산할 때 $O(N \log N)$이 걸리므로 $C$ 배열 전체를 모두 전처리하는 것은 $O(N^2 \log N)$ 시간에 할 수 있습니다.<br />점화식은 $O(N^2)$에 계산할 수 있으므로 전체 시간 복잡도는 $O(N^2 \log N)$입니다.</p> <h2 id="2-3-원숭이-백준-22032">2-3. 원숭이 (백준 22032)</h2> <h4 id="subtask-2-m-leq-5000-53점">Subtask 2. $M \leq 5\,000$ (53점)</h4> <p>원숭이가 잡을 수 있는 손잡이 쌍 $(x, y)$를 오름차순으로 정렬하면, 원숭이가 이동하는 경로는 정렬된 배열에서 인덱스가 증가하는 형태로 나타납니다. 그러므로 P 배열을 정렬합시다.</p> <p>$D(i)$를 $i$번째 순서쌍까지 도달했을 때 먹을 수 있는 바나나의 최대 개수라고 정의하면, $j &lt; i$이면서 $x_j = x_i$인 $j$에 대해 $D(i) \leftarrow D(j) + B_{y_i}$이고, $y_j = y_i$인 $j$에 대해 $D(i) \leftarrow D(j) + A_{x_i}$입니다. 점화식을 $O(N^2)$에 계산할 수 있습니다.</p> <h4 id="subtask-3-nm-leq-500000-150점">Subtask 3. $N,M \leq 500\,000$ (150점)</h4> <p>Subtask 2에서 세운 점화식을 $O(N^2)$보다 빠르게 계산해야 합니다.</p> <p>$i$번째 순서쌍까지 고려했을 때, 마지막에 잡은 기둥 A의 손잡이가 $x$이면서 먹을 수 있는 바나나의 최대 개수를 $L(i,x)$, 마지막에 잡은 기둥 B의 손잡이가 $y$이면서 먹을 수 있는 바나나의 최대 개수를 $R(i,y)$라고 정의합시다.<br />점화식은 $D(i) = \max\lbrace A_x + B_y, L(i-1,x)+B_y, A_x+R(i-1,y) \rbrace$, $L(i,x)\leftarrow L(i-1,x)+D(i)$, $R(i,y) \leftarrow R(i-1,y)+D(i)$입니다.<br />$L(i-1,\ast)$에서 $L(i,\ast)$로 전이할 때 값이 바뀌는 위치는 $x_i$ 밖에 없으므로 메모리를 $O(N)$만 사용할 수 있습니다. 마찬가지로 $R$ 배열도 메모리를 $O(N)$만 사용해서 표현할 수 있습니다.<br />P 배열을 정렬하는데 $O(M \log M)$이 걸리고, $D, L, R$ 배열을 계산하는 것은 $O(N)$이 걸리므로, 전체 시간 복잡도는 $O(N+M\log M)$입니다.</p> <h2 id="2-4-가로등-백준-22033">2-4. 가로등 (백준 22033)</h2> <p>풀이 준비 중</p>JusticeHui1차 2번(통신망), 2차 1번(총 쏘기), 2차 4번(가로등)은 아직 풀이가 준비되지 않았습니다.풀이가 준비되지 않은 세 문제는 모두 Petrozavodsk Programming Camp Winter 2022에 사용되었으며, 영어로 된 만점 풀이는 캠프 에디토리얼에서 확인할 수 있습니다. 통신망은 Critical Vertex, 총 쏘기는 Two Bullets, 가로등은 Streetlights입니다.2020년 국제정보올림피아드 선발고사 풀이2022-04-14T14:45:00+00:002022-04-14T14:45:00+00:00https://justicehui.github.io/koi/2022/04/14/2020tst<p>2020년 1월 17일과 7월 12일에 열린 선발고사 문제 풀이입니다.<br /> 1차 3번(지름길), 2차 2번(하나 둘 셋), 2차 3번(열차의 이동)은 아직 풀이가 준비되지 않았습니다.</p> <h2 id="1-1-문자열-찾기-백준-25008">1-1. 문자열 찾기 (백준 25008)</h2> <h4 id="subtask-1-n--m-8점">Subtask 1. $N = M$ (8점)</h4> <p>$f(S_i) = P_i$인 일대응 대응 함수 $f$가 존재하는지 확인하면 되고, $O(N)$에 해결할 수 있습니다.</p> <h4 id="subtask-3-n-leq-2000-25점">Subtask 3. $N \leq 2\,000$ (25점)</h4> <p>$S$의 길이가 $M$인 모든 부분 문자열에 대해 Subtask 1의 풀이를 적용하면 $O(NM)$에 해결할 수 있습니다.</p> <h4 id="subtask-4-n-leq-1000000-100점">Subtask 4. $N \leq 1\,000\,000$ (100점)</h4> <p>KMP 알고리즘을 생각해 봅시다. KMP 알고리즘은 패턴의 실패 함수를 구한 뒤, 원본 문자열과 패턴 문자열을 한 글자씩 비교하면서 매칭에 실패하는 경우 실패 함수를 따라가는 방식으로 진행합니다. 패턴 $P$가 문자열 $S$의 부분 문자열인지 판별하는 가장 기초적인 KMP 알고리즘의 구현은 다음과 같습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">GetFail</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span> <span class="o">&amp;</span><span class="n">P</span><span class="p">){</span> <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">P</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">Fail</span><span class="p">(</span><span class="n">n</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">while</span><span class="p">(</span><span class="n">j</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">P</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">P</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="n">j</span> <span class="o">=</span> <span class="n">Fail</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">];</span> <span class="k">if</span><span class="p">(</span><span class="n">P</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">P</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="n">Fail</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="o">++</span><span class="n">j</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="n">Fail</span><span class="p">;</span> <span class="p">}</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">KMP</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span> <span class="o">&amp;</span><span class="n">S</span><span class="p">,</span> <span class="k">const</span> <span class="n">string</span> <span class="o">&amp;</span><span class="n">P</span><span class="p">){</span> <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">S</span><span class="p">.</span><span class="n">size</span><span class="p">(),</span> <span class="n">m</span> <span class="o">=</span> <span class="n">P</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">Fail</span> <span class="o">=</span> <span class="n">GetFail</span><span class="p">(</span><span class="n">P</span><span class="p">),</span> <span class="n">R</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">while</span><span class="p">(</span><span class="n">j</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">!=</span> <span class="n">P</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="n">j</span> <span class="o">=</span> <span class="n">Fail</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">];</span> <span class="k">if</span><span class="p">(</span><span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">P</span><span class="p">[</span><span class="n">j</span><span class="p">]){</span> <span class="k">if</span><span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">==</span> <span class="n">m</span><span class="p">)</span> <span class="n">R</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">i</span><span class="o">-</span><span class="n">m</span><span class="o">+</span><span class="mi">1</span><span class="p">),</span> <span class="n">j</span> <span class="o">=</span> <span class="n">Fail</span><span class="p">[</span><span class="n">j</span><span class="p">];</span> <span class="k">else</span> <span class="n">j</span><span class="o">++</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="k">return</span> <span class="n">R</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <p>5번째 줄의 <code class="language-plaintext highlighter-rouge">P[i] == P[j]</code>는 단순히 <code class="language-plaintext highlighter-rouge">P[i]</code>와 <code class="language-plaintext highlighter-rouge">P[j]</code>가 동일한지 비교하는 것이 아닌, <code class="language-plaintext highlighter-rouge">P[0..j-1]</code>과 <code class="language-plaintext highlighter-rouge">P[i-j..i-1]</code>이 동치인 상황에서 한 글자씩 추가한<code class="language-plaintext highlighter-rouge">P[0..j]</code>와 <code class="language-plaintext highlighter-rouge">P[i-j..i]</code>가 동치인지 확인하는 부분입니다. 마찬가지로 14번째 줄의 <code class="language-plaintext highlighter-rouge">S[i] == P[j]</code>도 <code class="language-plaintext highlighter-rouge">P[0..j]</code>와 <code class="language-plaintext highlighter-rouge">S[i-j..i]</code>가 동치인지 확인하는 조건식입니다.<br />즉, <strong>사실상 같은 문자열</strong> $A, B$가 있을 때, 뒤에 각각 $a, b$를 붙인 $A+a$와 $B+b$가 <strong>사실상 같은 문자열</strong>인지 빠르게 확인할 수 있다면 KMP 알고리즘을 이용해 문제를 해결할 수 있습니다.</p> <p>만약 문자열 $A$에 이미 문자 $a$가 등장했다면 $a$는 매칭되어야 하는 짝이 정해져 있습니다. 반대로, 등장한 적이 없다면 아직 매칭되지 않은 임의의 문자와 매칭해도 됩니다.<br />이 정보는 각 문자마다 가장 최근에 등장한 위치를 저장하고 있다면 빠르게 처리할 수 있습니다. 구체적으로, <code class="language-plaintext highlighter-rouge">P[i]</code>가 <code class="language-plaintext highlighter-rouge">i</code> 이전에서 나온 가장 최근의 위치 <code class="language-plaintext highlighter-rouge">Prv[i]</code>를 알고 있다면 상수 시간에 <strong>사실상 같은 문자열</strong>인지 확인할 수 있습니다.</p> <p>전체 시간 복잡도는 $O(N+M)$입니다.</p> <h2 id="1-2-뚫기-백준-25009">1-2. 뚫기 (백준 25009)</h2> <h4 id="subtask-1-n-leq-3000-m-leq-3000-q1-7점">Subtask 1. $N \leq 3\,000, M \leq 3\,000, Q=1$ (7점)</h4> <p>사실 $M \leq 3\,000$ 조건이 없더라도 좌표 압축을 하면 $M = O(N)$으로 생각할 수 있습니다.</p> <p>$i-1$번째 줄에서 $(i, j)$로 이동하는 것은 $(i-1, k)$에서 앞으로 한 칸 전진해 $(i, k)$로 이동한 뒤, 비용이 $A$인 연산을 이용해 $(i, j)$로 이동하는, 두 개의 단계로 나눌 수 있습니다. DP 배열을 다음과 같이 정의하겠습니다.</p> <ul> <li>$D(2i, j) = $ 마지막에 앞으로 한 칸 전진해서 $(i, j)$에 도달하는 최소 비용</li> <li>$D(2i+1, j) = $ $(i, j)$에 도달하는 최소 비용</li> </ul> <p>$D(2i, j) = D(2i-1, j) + (0 \textit{ or } B)$이고, $D(2i+1,j) = \min\lbrace D(2i,j), D(2i,k)+A \rbrace$ 입니다. $O(N^2)$에 계산할 수 있습니다.</p> <h4 id="subtask-2-q-leq-50-29점">Subtask 2. $Q \leq 50$ (29점)</h4> <p>$D(i,\ast)$를 하나의 세그먼트 트리로 관리합니다. $D(i-1, \ast)$를 빠르게 $D(i, \ast)$로 바꾸는 방법을 찾아야 합니다.</p> <p>$D(2i,j) = D(2i-1, j) + B$는 막이 존재하는 구간에 $B$를 더하는 것과 동일하고, 이는 세그먼트 트리와 레이지 프로퍼게이션을 이용해 $O(\log N)$에 수행할 수 있습니다.<br />$D(2i+1,j) = \min\lbrace D(2i,j), D(2i,k)+A \rbrace$는 $D(2i,\ast)$의 최솟값 $D(2i,k)$를 구한 다음, 트리의 기존 값과 $D(2i,k)+A$ 중 더 작은 값으로 갱신해야 합니다. 이는 세그먼트 트리 비츠를 이용해 $O(\log N)$에 수행할 수 있습니다.</p> <p>각 쿼리를 $O(N \log N)$에 처리할 수 있으므로 전체 시간 복잡도는 $O(QN \log N)$입니다.</p> <h4 id="subtask-5-n-leq-10000-100점">Subtask 5. $N \leq 10\,000$ (100점)</h4> <p>Subtask 1/2의 풀이를 아무리 최적화해도 쿼리를 $O(N \log N)$보다 빠르게 처리할 수는 없어 보입니다. 대신, 각 연산을 각각 최대 $N$번만 사용해도 최적해를 찾을 수 있다는 점을 이용해 다른 풀이를 생각해 봅시다.</p> <p>만약 모든 $0 \leq i \leq N$에 대해, 비용이 $A$인 연산을 정확히 $i$번 사용했을 때 필요한 $B$ 연산의 횟수를 알고 있다면, $i$가 증가할수록 필요한 $B$ 연산의 횟수는 단조감소하므로 이분 탐색을 이용해 각 쿼리를 $O(\log N)$에 처리할 수 있습니다. 모든 $i$에 대해 직접 계산해보면 계산 방법에 따라 Subtask 3/4를 해결할 수 있습니다.</p> <p>도착점까지 갈 때 필요한 A 연산의 횟수 $a$와 B 연산의 횟수 $b$를 2차원 점 $(a, b)$로 나타내보면, 볼록 껍질의 <strong>왼쪽 아래 부분</strong>을 구성하는 점만 실제 정답이 될 수 있다는 것을 알 수 있습니다. 좌표 범위가 $X$일 때 볼록 껍질의 꼭짓점이 될 수 있는 정수 격자점은 최대 $O(X^{2/3})$개이기 때문에, $N+1$개의 점에서 모두 DP를 하는 것 대신 왼쪽 아래 껍질 상의 점에 대해서만 DP를 하면 시간 복잡도를 줄일 수 있습니다.</p> <p>필요한 점을 빠르게 찾는 방법을 알아봅시다. 먼저, x좌표가 가장 작은 왼쪽에 있는 점 $L$과 y좌표가 가장 작은 아래에 있는 점 $U$는 항상 껍질에 포함됩니다. 그러므로 두 점을 먼저 구합니다.<br />그 다음에는 $L$과 $U$를 잇는 직선과 평행한 껍질의 접선의 접점 $M$을 찾습니다. 다시 $L$과 $M$을 잇는 직선, $M$과 $U$를 잇는 직선의 기울기를 재귀적으로 처리하는 과정을 통해 모든 점을 찾아줄 수 있습니다.</p> <p>만약 <strong>주어진 기울기에 대한 볼록 껍질의 접점</strong>을 $T(N)$ 시간에 찾을 수 있다면 모든 점을 $O(N^{2/3}T(N))$에 구할 수 있습니다. 이때 $L$과 $U$는 기울기가 $1/0, 0/1$인 접선의 접점입니다.<br />기울기가 $-p/q\ (p,q \geq 0)$인 접점을 구하는 것은 A 연산의 비용이 $p$, B 연산의 비용이 $q$인 문제를 해결하는 것으로 생각할 수 있습니다. 이는 Subtask 2의 풀이를 이용해 $O(N \log N)$에 해결할 수 있습니다.</p> <p>$T(N) = O(N \log N)$이므로 $O(N^{2/3} \cdot N \log N)$에 모든 점을 계산할 수 있습니다. 쿼리는 $O(\log N)$에 처리할 수 있으므로 전체 시간 복잡도는 $O((N^{5/3} + Q) \log N)$입니다. 만약 세그먼트 트리 대신 평방 분할을 사용하면 $O(N^{13/6} + Q \log N)$이 됩니다.</p> <h2 id="1-3-지름길-백준-25010">1-3. 지름길 (백준 25010)</h2> <p>풀이 준비 중</p> <h2 id="1-4-칠하기-백준-25011">1-4. 칠하기 (백준 25011)</h2> <h4 id="subtask-2-nm-leq-1000-100점">Subtask 2. $N,M \leq 1\,000$ (100점)</h4> <p>가로 방향으로 연속한 칸 그룹과 세로 방향으로 연속한 칸 그룹을 정점으로 생각하면 방향 그래프를 만들 수 있습니다. 만들어진 모든 정점을 지나는 보행(walk)이 존재하는지 판별하는 문제로 생각할 수 있습니다.</p> <p>어떤 정점 $v$를 방문할 수 있다면 $v$와 같은 SCC에 속한 정점을 모두 방문할 수 있기 때문에 SCC를 압축한 DAG에서 문제를 해결해도 됩니다. DAG의 한 정점에서 출발해 모든 정점을 방문하는 walk가 있는지 판별하면 되고, Kosaraju’s Algorithm는 위상정렬 순서대로 SCC를 찾기 때문에 $i$번째 SCC에서 $i+1$번째 SCC로 가는 간선이 있는지 확인하면 됩니다.</p> <p>시간 복잡도는 $O(NM)$입니다.</p> <h2 id="2-1-마법의-다이얼-백준-25012">2-1. 마법의 다이얼 (백준 25012)</h2> <h4 id="subtask-1-3-n-leq-5000-26점">Subtask 1, 3. $N \leq 5\,000$ (26점)</h4> <p>$M$개의 다이얼 중 하나는 돌리지 않아도 최적해를 찾을 수 있습니다.</p> <p>$f(i,j)$를 $i$번째 다이얼을 돌리지 않으면서 $j$번째 줄에 $M$개의 점이 오도록 만드는 최소 비용이라고 정의합니다. $N$개의 모든 점에 대해 $f$를 계산한 뒤 최솟값을 취하면 되고, $f$는 매번 $O(N)$에 계산할 수 있습니다. 전체 시간 복잡도는 $O(N^2)$입니다.</p> <h4 id="subtask-2-m-leq-5000-r-leq-5000-41점">Subtask 2. $M \leq 5\,000,\ R \leq 5\,000$ (41점)</h4> <p>$f(j)$를 $j$번째 줄에 $M$개의 점이 오도록 만드는 최소 비용이라고 정의합시다. $f$는 매번 $O(N)$에 계산할 수 있습니다.<br />다이얼 하나를 고정하더라도 최적해를 찾을 수 있기 때문에, 실제로 확인해야 하는 $j$는 $\min(N,R)$가지입니다. $f(j)$는 각 다이얼마다 $j$와 가장 가까운 점을 찾아서 거리를 더하는 것으로 구할 수 있고, 이분 탐색을 이용해 $f(j)$를 $O(M \log N)$에 계산할 수 있습니다. 전체 시간 복잡도는 $O(RM \log N)$입니다.</p> <h4 id="subtask-4-n-leq-500000-r-leq-109-150점">Subtask 4. $N \leq 500\,000, R \leq 10^9$ (150점)</h4> <p>$f_i(j)$를 $i$번째 다이얼의 $j$번째 줄에 점이 오도록 만드는 최소 비용이라고 정의합시다. $f(j) = \sum f_i(j)$입니다.<br />함수 $f_i(j)$의 개형을 생각해보면, 기울기가 1 또는 -1인 <code class="language-plaintext highlighter-rouge">\/\/\/\...</code> 형태이고, 기울기가 바뀌는 지점은 점의 개수에 비례한다는 것을 알 수 있습니다. 그러므로 $f_i(j)$의 기울기가 바뀌는 지점과 변화량을 모두 구한다면 $f(j)$는 단순히 해당 정보들을 합쳐주는 것으로 구할 수 있습니다.</p> <p>$i$번째 다이얼의 $a_1 &lt; a_2 &lt; \cdots &lt; a_k$번째 줄에 점이 있다고 가정합시다. $a_x \leq j \leq a_{x+1}$인 $j$에 대해, $j \leq (a_x+a_{x+1})/2$이면 $f_i(j) = j-a_x$이고, $j \geq (a_x+a_{x+1})/2$이면 $f_i(j) = a_{x+1}-j$입니다. $j &lt; a_1 \lor j &gt; a_k$인 경우만 예외처리하면 됩니다.<br />함수 $f_i(j)$의 개형은 기울기가 1 또는 -1인 <code class="language-plaintext highlighter-rouge">\/\/\...</code> 형태라는 것을 알 수 있고, 기울기가 바뀌는 지점은 점의 개수에 비례한다는 것을 알 수 있습니다. 그러므로 $f_i(j)$의 기울기가 바뀌는 지점과 변화량을 모두 구하고, 이 정보들을 모두 합쳐서 $f(j)$ 함수를 만들 수 있습니다.</p> <p>기울기가 바뀌는 지점은 반정수이므로 2를 곱하면 쉽게 처리할 수 있습니다.</p> <p><code class="language-plaintext highlighter-rouge">std::map</code> 등을 이용해 $O(N \log N)$에 해결할 수 있습니다.</p> <h2 id="2-2-하나-둘-셋-백준-25013">2-2. 하나 둘 셋 (백준 25013)</h2> <p>풀이 준비 중</p> <h2 id="2-3-열차의-이동-백준-25014">2-3. 열차의 이동 (백준 25014)</h2> <p>풀이 준비 중</p> <h2 id="2-4-아이싱-백준-25015">2-4. 아이싱 (백준 25015)</h2> <h4 id="subtask-6-nm-leq-250000-150점">Subtask 6. $N,M \leq 250\,000$ (150점)</h4> <p><a href="https://justicehui.github.io/ps/2020/09/16/BOJ19862/">풀이</a></p>JusticeHui2020년 1월 17일과 7월 12일에 열린 선발고사 문제 풀이입니다. 1차 3번(지름길), 2차 2번(하나 둘 셋), 2차 3번(열차의 이동)은 아직 풀이가 준비되지 않았습니다.Rotating Sweep Line Technique (Bulldozer Trick)2022-03-30T14:59:00+00:002022-03-30T14:59:00+00:00https://justicehui.github.io/hard-algorithm/2022/03/30/rotate-sweep-line<h3 id="서론">서론</h3> <p>문제를 많이 풀어본 분들이라면 데이터가 정렬되어 있다는 것이 얼마나 좋은 성질인지 잘 알고 계실 것입니다. 이진 탐색을 이용할 수도 있고, 모든 원소가 서로 다른 배열에서 $A_i$보다 작은 가장 큰 원소와 같은 질의를 단순히 $A_{i-1}$을 반환하는 것으로 해결할 수 있습니다.<br /> 주어진 데이터가 정수와 같이 순서가 자명하게 정의되어 있다면 단순히 정렬하면 되지만, 2차원상의 점이라면 어떤 축을 기준으로 보느냐에 따라 정렬의 결과가 달라질 수 있습니다. 흔히 “불도저 트릭”이라고 불리는 이 테크닉은 서로 다른 정렬의 결과가 $O(N^2)$가지임을 보이고, 가능한 모든 정렬 결과를 $O(N^2 \log N)$에 순회하는 테크닉입니다.</p> <p>아직 널리 쓰이는 이름이 없습니다. 제 주변에서 많이 사용하는 명칭 두 개를 임의로 선택해 제목으로 정한 점 양해 부탁드립니다.</p> <h3 id="정렬의-경우의-수">정렬의 경우의 수</h3> <p>보통 점 $(x_i, y_i)$를 정렬하라고 하면 x좌표 오름차순으로 정렬합니다. 이 정렬 방법은 y축에 평행한 직선(기울기가 $\infty$인 직선)이 왼쪽부터 오른쪽으로 차례대로 이동하면서 만나는 점들에 순서대로 번호를 붙이는 것과 동일합니다. 마찬가지로, y좌표 내림차순으로 정렬하는 것은 x축에 평행한 직선(기울기가 $0$인 직선)이 한 방향으로 이동하면서 만나는 점들에 순서대로 번호를 붙이는 것입니다.<br /> 그러므로 서로 다른 정렬의 결과가 $O(N^2)$가지임을 보이는 것은, 정렬 기준으로 유효한 기울기가 $O(N^2)$개밖에 없다는 것을 보이면 됩니다.</p> <p><img src="https://i.imgur.com/rCZ8FgL.png" alt="" /></p> <p>정렬 기준 기울기를 아주 미세하게 변화시키더라도 정렬 결과는 바뀌지 않는다는 것은 직관적으로 알 수 있습니다. 아래 그림에서 초록색 화살표는 빨간색 화살표를 시계방향으로 4도 회전시킨 것이고, 정렬 결과가 바뀌지 않은 것을 확인할 수 있습니다.</p> <p><img src="https://i.imgur.com/O7BjTSc.png" alt="" /></p> <p>시계방향으로 계속 회전시키다 보면 4번 점과 5번 점을 잇는 선분과 평행해지는 시점에 4번 점과 5번 점의 우선순위가 동등해집니다. 이 상황에서 반시계방향으로 아주 조금 돌리면 x좌표가 더 작은 점이 앞에 오고, 시계방향으로 아주 조금 돌리면 x좌표가 더 큰 점이 앞에 오게 됩니다. 즉, 4번 점과 5번 점을 잇는 선분의 기울기를 기점으로 정렬 결과가 달라집니다.<br /> 그다음은 2번 점과 3번 점을 잇는 선분과 평행해지는 시점에 두 점의 순서가 바뀝니다.</p> <p><img src="https://i.imgur.com/FpuDkK7.png" alt="" /></p> <p>위 그림에서 알 수 있듯, 정렬 기준과 두 점을 잇는 선분과 평행해지는 시점에만 정렬 결과가 달라집니다. 또한 세 점이 한 직선 위에 존재하지 않는다면 항상 두 점의 순서만 바뀌고, 순서가 바뀌는 두 점은 정렬 순서상에서 인접합니다. 한 점을 기준으로 여러 기울기를 그렸을 때 자신보다 앞에 있는 점 집합과 뒤에 있는 점 집합이 어떻게 변화하는지 살펴보면 쉽게 알 수 있습니다.<br /> 두 점을 잇는 선분의 기울기만 봐도 모든 정렬의 결과를 확인할 수 있으므로, 가능한 정렬 결과의 경우의 수는 $O(N^2)$가지입니다. $O(N^2)$개의 기울기를 모두 구해서 정렬한 다음, 차례대로 순회하면서 점들의 순서를 바꾸는 방식으로 구현합니다.</p> <video autoplay="" controls="" loop="" preload="auto" style="max-width:100%"> <source src="/img/rotating-sweep-line.mp4" type="video/mp4" /> </video> <h3 id="활용">활용</h3> <p>구현 방법은 뒤에서 살펴보고, 이 테크닉을 어디에 활용할 수 있을지 먼저 알아보겠습니다.</p> <h4 id="boj-9484-최대삼각형-최소삼각형">BOJ 9484. 최대삼각형, 최소삼각형</h4> <p>$N$개의 점이 주어졌을 때, 3개의 점을 선택해서 만들 수 있는 삼각형 중 넓이의 최댓값과 최솟값을 구하는 문제입니다.</p> <p>삼각형의 넓이는 밑변의 길이와 높이의 곱을 2로 나눠서 구할 수 있습니다. 만약 밑변으로 사용할 두 꼭짓점을 고정한다면, 두 꼭짓점을 잇는 직선과 가장 가까운 점을 선택하면 최소 넓이 삼각형을 얻을 수 있습니다. 마찬가지로 직선과 가장과 가장 먼 점을 선택하면 최대 넓이를 얻을 수 있습니다.</p> <p>이 문제는 Rotating Sweep Line을 이용해 해결할 수 있습니다. 두 점을 잇는 선분의 기울기를 기준으로 정렬했고, 두 점의 번호를 각각 $u, v\ (u &lt; v)$라고 하겠습니다. 두 점을 잇는 직선과 가장 가까운 점은 $u-1, v+1$ 중 하나이며, 가장 먼 점은 $1, N$ 중 하나입니다. 그러므로 단순히 점들의 정렬 순서만 관리하면 이 문제를 해결할 수 있습니다.</p> <h4 id="boj-3121-빨간점-파란점">BOJ 3121. 빨간점, 파란점</h4> <p>좌표 평면 위에 빨간 점과 파란 점이 주어집니다. 평행선 사이에 파란 점이 존재하지 않도록 두 평행선을 그었을 때, 평행선 사이에 들어갈 수 있는 빨간 점 개수의 최댓값을 구하는 문제입니다.</p> <p>평행선의 기울기를 기준으로 정렬했을 때 인접한 점이 두 평행선 사이에 함께 들어갑니다. 그러므로 기울기를 고정했다면, 수열에서 0이 포함되지 않고 1로만 구성된 가장 긴 연속 부분 수열을 구하는 문제라고 생각할 수 있습니다. 이러한 문제는 흔히 금광 세그라고 불리는 세그먼트 트리를 이용해 쉽게 해결할 수 있습니다.</p> <p>$O(N^2)$개의 기울기에 대해 모두 수열에서의 문제를 푸는 것도 어렵지 않게 할 수 있습니다. 기울기마다 순서가 바뀌는 점은 2개이므로, 단순히 세그먼트 트리에서 리프 정점의 정보를 갱신하는 것으로 정렬 결과의 변화를 반영할 수 있습니다. 따라서 $O(N^2 \log N)$에 문제를 해결할 수 있습니다.</p> <h3 id="구현">구현</h3> <p>세 점 이상이 한 직선 위에 있는 경우, 해당 기울기에서 그들의 순서를 바꾸는 것은 구간을 뒤집는 것으로 생각할 수 있습니다.</p> <p><img src="https://i.imgur.com/SSGziv5.png" alt="" /></p> <p>정렬 순서상에서 인접한 점끼리만 위치를 교환해야 하기 때문에 평행한 선분을 아무 순서대로 처리하면 안 됩니다. $i, i+1, \cdots, j$번 점을 뒤집을 때, 먼저 $i$를 $i+1,\cdots,j$와 교환해서 맨 뒤로 보내고, $i+1$를 $i+2,\cdots,j$와 교환해서 뒤로 보내는 식으로 구간을 뒤집으면 됩니다.</p> <p>아래 코드는 BOJ 9484. 최대삼각형, 최소삼각형의 코드입니다. 점들의 초기 인덱스는 x좌표 오름차순으로 정렬했을 때의 순서로 정의했습니다.<br /> 기울기가 같은 선분을 잘 처리하기 위해서 23번째 줄에서 기울기가 같은 경우, 선분이 연결하는 두 점의 초기 인덱스를 비교해서 정렬합니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="k">using</span> <span class="n">ll</span> <span class="o">=</span> <span class="kt">long</span> <span class="kt">long</span><span class="p">;</span> <span class="k">struct</span> <span class="nc">Point</span><span class="p">{</span> <span class="n">ll</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">;</span> <span class="kt">bool</span> <span class="k">operator</span> <span class="o">&lt;</span> <span class="p">(</span><span class="k">const</span> <span class="n">Point</span> <span class="o">&amp;</span><span class="n">p</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">tie</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">tie</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">p</span><span class="p">.</span><span class="n">y</span><span class="p">);</span> <span class="p">}</span> <span class="kt">bool</span> <span class="k">operator</span> <span class="o">==</span> <span class="p">(</span><span class="k">const</span> <span class="n">Point</span> <span class="o">&amp;</span><span class="n">p</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">tie</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="o">==</span> <span class="n">tie</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">p</span><span class="p">.</span><span class="n">y</span><span class="p">);</span> <span class="p">}</span> <span class="p">};</span> <span class="k">struct</span> <span class="nc">Line</span><span class="p">{</span> <span class="n">ll</span> <span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">dx</span><span class="p">,</span> <span class="n">dy</span><span class="p">;</span> <span class="c1">// i &lt; j, dx &gt;= 0</span> <span class="n">Line</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="kt">int</span> <span class="n">j</span><span class="p">,</span> <span class="k">const</span> <span class="n">Point</span> <span class="o">&amp;</span><span class="n">pi</span><span class="p">,</span> <span class="k">const</span> <span class="n">Point</span> <span class="o">&amp;</span><span class="n">pj</span><span class="p">)</span> <span class="o">:</span> <span class="n">i</span><span class="p">(</span><span class="n">i</span><span class="p">),</span> <span class="n">j</span><span class="p">(</span><span class="n">j</span><span class="p">),</span> <span class="n">dx</span><span class="p">(</span><span class="n">pj</span><span class="p">.</span><span class="n">x</span><span class="o">-</span><span class="n">pi</span><span class="p">.</span><span class="n">x</span><span class="p">),</span> <span class="n">dy</span><span class="p">(</span><span class="n">pj</span><span class="p">.</span><span class="n">y</span><span class="o">-</span><span class="n">pi</span><span class="p">.</span><span class="n">y</span><span class="p">)</span> <span class="p">{}</span> <span class="c1">// dy / dx &lt; l.dy / l.dx</span> <span class="kt">bool</span> <span class="k">operator</span> <span class="o">&lt;</span> <span class="p">(</span><span class="k">const</span> <span class="n">Line</span> <span class="o">&amp;</span><span class="n">l</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> <span class="n">ll</span> <span class="n">le</span> <span class="o">=</span> <span class="n">dy</span> <span class="o">*</span> <span class="n">l</span><span class="p">.</span><span class="n">dx</span><span class="p">,</span> <span class="n">ri</span> <span class="o">=</span> <span class="n">l</span><span class="p">.</span><span class="n">dy</span> <span class="o">*</span> <span class="n">dx</span><span class="p">;</span> <span class="k">return</span> <span class="n">tie</span><span class="p">(</span><span class="n">le</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">tie</span><span class="p">(</span><span class="n">ri</span><span class="p">,</span> <span class="n">l</span><span class="p">.</span><span class="n">i</span><span class="p">,</span> <span class="n">l</span><span class="p">.</span><span class="n">j</span><span class="p">);</span> <span class="p">}</span> <span class="kt">bool</span> <span class="k">operator</span> <span class="o">==</span> <span class="p">(</span><span class="k">const</span> <span class="n">Line</span> <span class="o">&amp;</span><span class="n">l</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">dy</span> <span class="o">*</span> <span class="n">l</span><span class="p">.</span><span class="n">dx</span> <span class="o">==</span> <span class="n">l</span><span class="p">.</span><span class="n">dy</span> <span class="o">*</span> <span class="n">dx</span><span class="p">;</span> <span class="p">}</span> <span class="p">};</span> <span class="n">ll</span> <span class="nf">TriangleArea</span><span class="p">(</span><span class="k">const</span> <span class="n">Point</span> <span class="o">&amp;</span><span class="n">p1</span><span class="p">,</span> <span class="k">const</span> <span class="n">Point</span> <span class="o">&amp;</span><span class="n">p2</span><span class="p">,</span> <span class="k">const</span> <span class="n">Point</span> <span class="o">&amp;</span><span class="n">p3</span><span class="p">){</span> <span class="n">ll</span> <span class="n">cross</span> <span class="o">=</span> <span class="p">(</span><span class="n">p2</span><span class="p">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">p1</span><span class="p">.</span><span class="n">x</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="n">p3</span><span class="p">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">p2</span><span class="p">.</span><span class="n">y</span><span class="p">)</span> <span class="o">-</span> <span class="p">(</span><span class="n">p3</span><span class="p">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">p2</span><span class="p">.</span><span class="n">x</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="n">p2</span><span class="p">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">p1</span><span class="p">.</span><span class="n">y</span><span class="p">);</span> <span class="k">return</span> <span class="n">abs</span><span class="p">(</span><span class="n">cross</span><span class="p">);</span> <span class="p">}</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">Pos</span><span class="p">[</span><span class="mi">2020</span><span class="p">];</span> <span class="n">Point</span> <span class="n">A</span><span class="p">[</span><span class="mi">2020</span><span class="p">];</span> <span class="kt">void</span> <span class="nf">Solve</span><span class="p">(){</span> <span class="n">sort</span><span class="p">(</span><span class="n">A</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">A</span><span class="o">+</span><span class="n">N</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">Pos</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">Line</span><span class="o">&gt;</span> <span class="n">V</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="n">V</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="n">j</span><span class="p">]);</span> <span class="n">sort</span><span class="p">(</span><span class="n">V</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">V</span><span class="p">.</span><span class="n">end</span><span class="p">());</span> <span class="n">ll</span> <span class="n">Min</span> <span class="o">=</span> <span class="mh">0x3f3f3f3f3f3f3f3f</span><span class="p">,</span> <span class="n">Max</span> <span class="o">=</span> <span class="mh">0xc0c0c0c0c0c0c0c0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">V</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">=</span><span class="n">j</span><span class="p">){</span> <span class="k">while</span><span class="p">(</span><span class="n">j</span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">V</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">V</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="n">j</span><span class="o">++</span><span class="p">;</span> <span class="c1">// [i, j) -&gt; same slope</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">k</span><span class="o">=</span><span class="n">i</span><span class="p">;</span> <span class="n">k</span><span class="o">&lt;</span><span class="n">j</span><span class="p">;</span> <span class="n">k</span><span class="o">++</span><span class="p">){</span> <span class="kt">int</span> <span class="n">u</span> <span class="o">=</span> <span class="n">V</span><span class="p">[</span><span class="n">k</span><span class="p">].</span><span class="n">i</span><span class="p">,</span> <span class="n">v</span> <span class="o">=</span> <span class="n">V</span><span class="p">[</span><span class="n">k</span><span class="p">].</span><span class="n">j</span><span class="p">;</span> <span class="c1">// point id</span> <span class="n">swap</span><span class="p">(</span><span class="n">Pos</span><span class="p">[</span><span class="n">u</span><span class="p">],</span> <span class="n">Pos</span><span class="p">[</span><span class="n">v</span><span class="p">]);</span> <span class="n">swap</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">Pos</span><span class="p">[</span><span class="n">u</span><span class="p">]],</span> <span class="n">A</span><span class="p">[</span><span class="n">Pos</span><span class="p">[</span><span class="n">v</span><span class="p">]]);</span> <span class="k">if</span><span class="p">(</span><span class="n">Pos</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">Pos</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="n">swap</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="n">Pos</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">){</span> <span class="n">Min</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">Min</span><span class="p">,</span> <span class="n">TriangleArea</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">Pos</span><span class="p">[</span><span class="n">u</span><span class="p">]],</span> <span class="n">A</span><span class="p">[</span><span class="n">Pos</span><span class="p">[</span><span class="n">v</span><span class="p">]],</span> <span class="n">A</span><span class="p">[</span><span class="n">Pos</span><span class="p">[</span><span class="n">u</span><span class="p">]</span><span class="o">-</span><span class="mi">1</span><span class="p">]));</span> <span class="n">Max</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">Max</span><span class="p">,</span> <span class="n">TriangleArea</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">Pos</span><span class="p">[</span><span class="n">u</span><span class="p">]],</span> <span class="n">A</span><span class="p">[</span><span class="n">Pos</span><span class="p">[</span><span class="n">v</span><span class="p">]],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]));</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">Pos</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">N</span><span class="p">){</span> <span class="n">Min</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">Min</span><span class="p">,</span> <span class="n">TriangleArea</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">Pos</span><span class="p">[</span><span class="n">u</span><span class="p">]],</span> <span class="n">A</span><span class="p">[</span><span class="n">Pos</span><span class="p">[</span><span class="n">v</span><span class="p">]],</span> <span class="n">A</span><span class="p">[</span><span class="n">Pos</span><span class="p">[</span><span class="n">v</span><span class="p">]</span><span class="o">+</span><span class="mi">1</span><span class="p">]));</span> <span class="n">Max</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">Max</span><span class="p">,</span> <span class="n">TriangleArea</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">Pos</span><span class="p">[</span><span class="n">u</span><span class="p">]],</span> <span class="n">A</span><span class="p">[</span><span class="n">Pos</span><span class="p">[</span><span class="n">v</span><span class="p">]],</span> <span class="n">A</span><span class="p">[</span><span class="n">N</span><span class="p">]));</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">Min</span><span class="o">/</span><span class="mi">2</span> <span class="o">&lt;&lt;</span> <span class="s">"."</span> <span class="o">&lt;&lt;</span> <span class="n">Min</span><span class="o">%</span><span class="mi">2</span><span class="o">*</span><span class="mi">5</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">Max</span><span class="o">/</span><span class="mi">2</span> <span class="o">&lt;&lt;</span> <span class="s">"."</span> <span class="o">&lt;&lt;</span> <span class="n">Max</span><span class="o">%</span><span class="mi">2</span><span class="o">*</span><span class="mi">5</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="k">while</span><span class="p">(</span><span class="nb">true</span><span class="p">){</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">N</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">x</span> <span class="o">&gt;&gt;</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">y</span><span class="p">;</span> <span class="n">Solve</span><span class="p">();</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <h3 id="연습-문제">연습 문제</h3> <p><a href="https://www.acmicpc.net/workbook/view/3610">https://www.acmicpc.net/workbook/view/3610</a></p>JusticeHui서론 문제를 많이 풀어본 분들이라면 데이터가 정렬되어 있다는 것이 얼마나 좋은 성질인지 잘 알고 계실 것입니다. 이진 탐색을 이용할 수도 있고, 모든 원소가 서로 다른 배열에서 $A_i$보다 작은 가장 큰 원소와 같은 질의를 단순히 $A_{i-1}$을 반환하는 것으로 해결할 수 있습니다. 주어진 데이터가 정수와 같이 순서가 자명하게 정의되어 있다면 단순히 정렬하면 되지만, 2차원상의 점이라면 어떤 축을 기준으로 보느냐에 따라 정렬의 결과가 달라질 수 있습니다. 흔히 “불도저 트릭”이라고 불리는 이 테크닉은 서로 다른 정렬의 결과가 $O(N^2)$가지임을 보이고, 가능한 모든 정렬 결과를 $O(N^2 \log N)$에 순회하는 테크닉입니다.2022 숭고한 연합 알고리즘 대회 후기2022-03-27T14:00:00+00:002022-03-27T14:00:00+00:00https://justicehui.github.io/review/2022/03/27/skh<h2 id="서론">서론</h2> <p>3달 동안 준비한 숭고한 연합 알고리즘 대회가 드디어 끝났습니다. 저는 Div.1의 가장 어려운 문제, Div.2의 두 번째로 어려운 문제, Div.3의 가장 어려운 문제를 출제하고, 문제의 선제와 검수를 총괄했습니다. 대회 종료 후 풀이 방송도 담당했습니다.<br /> 올해 초에 대회 준비를 시작할 때부터 주변 지인들에게 때려치우고 싶다고 1시간에 한 번씩 징징거렸는데 대회가 끝나고 나니 속이 후련하네요.<br /> 운영진에 합류하게 된 과정부터 대회 풀이 방송까지, 여러 가지 이야기를 풀어보도록 하겠습니다.</p> <h2 id="운영진-합류">운영진 합류</h2> <p>원래 이 대회는 2월에 개최될 예정이었고, 저는 2월까지 1학년 신분이기 때문에 대회에 참가하려고 했습니다. 하지만 제가 운영하지 않으면 사람이 없어서 대회가 안 열린다는 이야기를 듣고 눈물을 흘리며 운영진에 합류하게 되었습니다.</p> <p>대회 코디네이터 역할을 맡은 것이라고 기대했지만 대회에 낼 문제가 부족해서 출제도 하게 되었습니다. 짧은 시간 동안 급하게 아이디어를 짜내다 보니 재미없는 문제만 2개 나왔습니다. 별로 대회에 내고 싶지 않았지만 어쩌다 보니 두 문제 모두 대회에 출제되었습니다.</p> <p>출제했다고 코디네이터를 안 해도 되는 건 아니었습니다. 운영진 중 대회 운영 경험이 가장 많았기 때문에 문제 선제와 검수를 총괄했습니다. 문제 선제 회의 진행을 도와주신 2021년 고려대학교 ALPS의 회장이자 BOJ 연말 대회의 핵심 운영진인 Ryute님과, 예산이 적어 검수비를 많이 드리지 못하는 상황임에도 기꺼이 검수를 도와주신 7명의 외부 검수진 덕분에 문제를 완성할 수 있었습니다.</p> <p>BOJ 측에 연락할 때 일개 운영진인 줄 알았던 제가 대회 개최자로 지정되어서 BOJ Stack도 제가 관리하게 되었습니다. 맨날 하는 일이라서 별로 부담이 되지 않았습니다.</p> <p>대회 풀이 방송도 제가 하게 되었고, 방송에서 사용할 문제 풀이 슬라이드 제작도 자연스럽게 제 담당이 되었습니다. 출제자가 풀이를 적어주면 제가 문장을 다듬고 내용을 적당히 수정해서 슬라이드에 넣었습니다.</p> <p>대회 문제와 관련된 대부분의 일을 제가 처리한 대신 행정적인 업무는 2021년 한양대학교 ALOHA 회장이신 dksu40님께서 담당해 주셨습니다. 정말 감사합니다.</p> <h2 id="문제-출제-과정---통행량-조사">문제 출제 과정 - 통행량 조사</h2> <p>Div.3의 마지막 문제(H)이자 Div.2의 G번 문제로 출제된 통행량 조사 문제는 제가 좋아하는 Unicycle Graph가 등장하는 문제입니다. 마침 한양대역이 있는 수도권 지하철 2호선이 Unicycle이라서 지문도 편하게 작성했습니다.</p> <p>원래 이 문제는 HLD를 활용한 $O(Q \log^2 N)$ 풀이를 막으려고 했지만 BOJ의 채점 서버가 너무 좋아서 실패했습니다. 분명 Codeforces Polygon에서는 막혔는데… Intel Xeon을 쓰는 BOJ에 비해 Polygon은 i3를 써서 캐시 메모리의 크기에서 차이가 발생하는 것 같습니다.</p> <p>이번 숭고한 연합 알고리즘 대회는 현대모비스의 후원을 받아 진행되었습니다. 기업을 소재로 한 문제를 만들어야 했고, 교통망과 관련된 이 문제가 후원 문제로 선정되었습니다. 덕분에 지문을 다시 썼습니다. 현대 오토에버의 후원을 받은 Hello, BOJ 2022!의 <a href="https://www.acmicpc.net/problem/24273">교통량 분석</a> 문제의 지문을 많이 참고했습니다.</p> <p>데이터는 Good Bye, BOJ 2020!에 출제했던 <a href="https://www.acmicpc.net/problem/20530">양분</a> 문제의 데이터를 재활용했습니다.</p> <p>아래 목록은 제가 작성한 솔루션 코드의 <strong>일부</strong>입니다. $O(N+Q)$, $O(N\log N+Q)$, $O(N+Q\log N)$, $O((N+Q)\log N)$, $O(N+Q\log^2 N)$ 등 다양한 복잡도의 풀이가 존재합니다.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># O((N+Q) log N) ac-hui.cpp sparse table을 이용한 O(log N) LCA # O(N log N + Q) ac-fast-lca.cpp ac-hui에서 LCA를 전처리 O(N log N), 쿼리 O(1)에 처리 # O(N + Q) ac-linear.cpp ac-hui에서 LCA를 전처리 O(N), 쿼리 O(1)에 처리 # O(N + Q log N) ac-hld-lca.cpp ac-hui에서 LCA를 HLD로 구함 ac-hld-prefix.cpp HLD + Prefix Sum # O(N + Q log^2 N) slow-hld-seg.cpp HLD + Segment Tree slow-hld-fenwick.cpp HLD + Fenwick Tree slow-hld-lazy.cpp HLD + Segment Teee Lazy Propagation # TLE naive-dfs.cpp 백트래킹으로 경로 찾음 naive-path.cpp O(NQ), 간선 가중치를 naive하게 갱신 naive-perm.cpp O(QN!) </code></pre></div></div> <h2 id="문제-출제-과정---dcmsf">문제 출제 과정 - DCMSF</h2> <p>Div.1의 마지막 문제(H)로 출제된 DCMSF는 모르면 못 풀고 알면 쉽게 풀리는 전형적인 사전지식 문제라서 정말 대회에 내고 싶지 않았습니다. 다들 풀이를 먼저 고정해놓고 문제를 만들었다고 생각할 텐데, 사실 문제를 만들고 풀이를 생각한 문제입니다.</p> <p>2021 Winter SUAPC에 <a href="https://www.acmicpc.net/problem/20927">Degree Bounded Minimum Spanning Tree</a>라는 문제가 출제되었는데, 이 문제처럼 정점 차수에 제한이 있는 스패닝 트리를 구하는 것은 k = 2면 해밀턴 경로 문제로 reduction 되기 때문에 NP-Complete입니다. 여기에 조건을 적당히 붙여서 다항 시간에 풀 수 있는 문제를 만들고 싶었고, 이렇게 해서 나온 문제가 DCMSF입니다.</p> <p>처음에는 차수 제한이 1일 때 MST를 구하는 문제였습니다. 이건 왼쪽에 제한이 걸린 정점, 오른쪽에 나머지 정점을 놓고, 오른쪽에서 MST를 구한 다음에 Kuhn-munkres algorithm이나 MCMF 등으로 가중치 이분 매칭을 해서 해결할 수 있습니다.</p> <p>이틀 정도 문제를 고민하다 보니 트리 조건과 차수 조건이 각각 matroid라서 matroid intersection 으로도 문제를 해결할 수 있다는 것을 알게 되었습니다. 그리고 조금 더 고민해보니 트리 조건과 차수 1 제한 조건이 함께 있어도 matroid라서 단순한 그리디로 풀린다는 것을 깨달았습니다.<br /> 이렇게 문제를 버릴 수는 없어서 차수 $K_i$ 제한 조건을 추가해서 matroid intersection 문제로 만들었습니다.</p> <p>문제를 검수할 사람이 없었는데, 외부 검수진으로 참여하신 dennisstar님과 cs71107님에게 matroid를 강제로 공부시켜서 검수를 하게 했습니다. 정말 감사합니다.</p> <p>TMI) 일반적으로 3개 이상의 matroid intersection은 해밀턴 경로 문제로 reduction 할 수 있어서 다항 시간에 해결할 수 없습니다. 유향 그래프에서 간선 집합 $E$에서 $\mathcal{I}_1$을 모든 정점의 in-degree가 1 이하인 간선 집합, $\mathcal{I}_2$를 모든 정점의 out-degree가 1 이하인 간선 집합, $\mathcal{I_3}$를 방향을 무시했을 때 forest가 되는 간선 집합이라고 정의하면 해밀턴 경로 문제가 됩니다.</p> <h2 id="문제-검수">문제 검수</h2> <p>문제는 총 16문제였고 그중 제가 2문제를 출제했기 때문에 남은 14문제를 검수해야 하는 상황이었습니다. 문제별로 간단한 코멘트를 작성해 봅니다.</p> <p>Div.2는 완전 탐색과 그래프 이론, Div.1은 사전 지식 문제가 많이 나와서 셋의 밸런스가 좋지 않다는 것을 알고 있었지만, 대부분의 시간을 문제에 오류가 없도록 하는 것에 투자하느라 밸런스를 맞추려는 시도조차 하지 못했습니다. 이밖에도 전체적으로 문제 지문의 상태가 별로 좋지 않고 그냥 문제가 재미없다는 점 등 여러 이슈가 있었는데, 제가 별로 대회에 의욕이 없어서 그런지 알고 있음에도 불구하고 고치지 않았습니다. 여러 채널로 대회에 대한 피드백이 들어오고 있는데, 문제가 너무 안 좋다고 느껴졌다면 제 탓이니까 저를 욕하시면 됩니다.</p> <details> <summary><b>문제별 코멘트 (노잼 주의, 펼치기/닫기)</b></summary> <h4 id="div2a-">Div.2A 자동완성</h4> <p>현대모비스를 소재로 한 통행량 조사 문제처럼 Naver D2를 소재로 한 문제입니다. 저는 이 문제의 지문을 작성했습니다.</p> <h4 id="div2b--">Div.2B 장작 넣기</h4> <p>원래 Div.2D에 출제할 예정이었지만 다른 문제가 더 어려워서 앞으로 이동했습니다. 스코어보드를 보면 좋은 선택이었다고 생각합니다.</p> <p>문제를 잘 읽으면 완전 탐색을 이용해 간단하게 해결할 수 있습니다. 알고리즘을 처음 공부하는 분들은 대부분 완전 탐색을 구현하는 것에 익숙하지 않아서 많이 고전할 것이라 예상했지만, 이 점을 대회 4일 전에 깨달아서 손을 쓸 수 없었습니다. 죄송합니다.</p> <h4 id="div2c-">Div.2C 주식</h4> <p>대회 시작 30분 전에 풀이에 오류가 발견된 문제입니다. 기존에는 매수/매도의 양을 자유롭게 결정할 수 있고 대출도 최대 $K$배 만큼 자유롭게 할 수 있었는데, 급하게 영끌 대출/풀매수/풀매도로 수정했습니다. ahgus89님 정말 감사합니다.</p> <p>지문을 꼼꼼하게 읽지 않으면 많이 틀리기 좋은 문제고, 저도 검수하면서 많이 틀렸습니다. 장작 넣기처럼 완전 탐색을 이용해 해결할 수 있습니다.</p> <h4 id="div2d-skh-">Div.2D SKH 문자열</h4> <p>원래 Div.2B에 출제할 예정이었지만 너무 어려워서 장작 넣기와 위치를 바꿨습니다.</p> <h4 id="div2e--">Div.2E 최대한의 휴식</h4> <p>드디어 완전 탐색이 아닌 문제가 나왔습니다. 문제를 많이 풀어봤다면 기계적으로 풀 수 있는 문제고, 많이 안 풀어봤으면 어려운 문제인 것 같습니다. 처음에 지문을 이해하기 어려웠는데 다른 검수자들은 잘 푸는 것 같아서 딱히 수정하지는 않았습니다.</p> <h4 id="div2f--">Div.2F 노트 조각</h4> <p>교육적인 측면에서 봤을 때, Div.2에서 가장 좋은 문제라고 생각합니다. 이 문제도 문제를 많이 풀어봤다면 기계적으로 풀 수 있습니다. DE에 비해 전형적인 유형이라 그런지 문제 포지션에 비해 많이 풀렸습니다.</p> <p>원래 Bellman-Ford와 SPFA의 저격 데이터를 만들려고 했는데 귀찮아서 TLE 나와야 하는 코드만 올리고 방치했습니다. 결국 대회 4일 전에 출제자가 직접 저격 데이터를 만들었습니다.</p> <h4 id="div2g--">Div.2G 통행량 조사</h4> <p>노잼 문제</p> <h4 id="div2h--">Div.2H 원형 게임</h4> <p>원래 Good Bye, BOJ 2021 / Hello, BOJ 2022 후보 문제였는데 숭고한에 나오게 되었습니다. 제가 검수를 시작할 시점에는 이미 잘 완성되어 있어서 딱히 건든 부분이 없습니다.</p> <h4 id="div1a--">Div.1A 단어 마방진</h4> <p>원래 가지치기를 열심히 해야 하는 백트래킹 문제였지만, 올라온 솔루션마다 TLE 데이터가 튀어나오면서 단순한 완전 탐색 문제가 되었습니다.</p> <h4 id="div1b--">Div.1B 이차 함수</h4> <p>왠지 될 것 같은 풀이를 짜면 통과되는 문제입니다. Div.2에 나와도 될 난이도지만 모듈러 곱셈 역원 때문에 Div.1에 나오게 되었습니다. 다행히 Div.1에서는 페르마 소정리라는 지식이 걸림돌이 되지 않은 것 같습니다.</p> <p>고등학생 때 학교 공부를 안 했더니 풀이 증명하는 데 애를 먹었습니다. 아 미적분 너무 어려워…</p> <h4 id="div1c--">Div.1C 캐슬 디펜스</h4> <p>제가 검수를 시작할 시점에 이미 잘 완성되어 있어서 건들지 않았습니다.</p> <p>$ak-bt$가 최소가 되는 $(k, t)$를 2차원 좌표 평면에 찍으면 Convex Hull이 나오는 것을 이용해 새로운 문제를 만들 수 있을 것 같은데… 1시간 정도 고민했는데 좋은 아이디어가 안 떠올라서 포기했습니다.</p> <h4 id="div1d-">Div.1D 내적</h4> <p>식을 만지다 보면 전형적인 문제로 바뀝니다. 개인적으로 식을 잘 변형하는 것이 어려웠는데 많이 풀려서 놀랐습니다.</p> <p>오버플로우/실수 오차 때문에 좌표 범위를 더 키우지 못해 아쉬웠습니다.</p> <h4 id="div1e-">Div.1E 다트</h4> <p>원래 이 문제가 Div.1D에 나올 예정이었지만, 미리 작성된 코드 없이 이 문제를 푸는 것은 매우 어렵다고 생각해서 내적과 위치를 바꿨습니다. 사전에 작성한 코드가 있다면 두 문제의 난이도가 비슷합니다.</p> <p>2019 경기과학고 송년대회의 <a href="https://www.acmicpc.net/problem/18190">촛불과 그림자</a>의 하위 호환으로, 풀이를 떠올리기는 굉장히 쉽지만 구현이 고통스러운 기하 문제입니다. 2018 ICPC World Final 은메달리스트인 <a href="https://zigui.tistory.com/5">서울대학교 MolaMola팀의 팀노트</a> 덕분에 편하게 검수했습니다.</p> <h4 id="div1f---">Div.1F 르블랑의 트리 순회</h4> <p>검수 안 했습니다.</p> <h4 id="div1g--">Div.1G 숲 게임</h4> <p>BBST를 직접 구현해서 $O(N \log N)$ 솔루션을 작성하려고 했는데 귀찮아서 안 했습니다. 출제자가 의도한 풀이는 $O(N\log^2 N)$입니다.</p> <h4 id="div1h-dcmsf">Div.1H DCMSF</h4> <p>쓰레기 문제</p> </details> <h2 id="풀이-방송">풀이 방송</h2> <p>작년부터 알고리즘 강의를 비대면으로 하고 있기 때문에 마이크와 타블렛 같은 기본적인 장비는 이미 준비가 되어 있었습니다. 예전에 심심풀이로 문제 푸는 방송을 한 적이 있기 때문에 트위치 계정도 있고, OBS Studio도 사용할 수 있습니다. 그러다 보니 풀이 방송도 담당하게 되었습니다.</p> <p>풀이 슬라이드는 UCPC 2020에서 했던 것처럼 overleaf에서 제작했고, 문제 해설은 마찬가지로 UCPC 2020에서 했던 것처럼 drawable pdf를 사용했습니다. 대회 스폰서 중 하나인 CorcaAI의 홍보 세션은 Zoom 회의를 트위치로 송출하는 방식으로 진행했습니다.</p> <p>방송에 있어서 아쉬운 부분이 많이 있습니다. UCPC처럼 여러 레이아웃을 만들어서 깔끔하게 하고 싶었는데 제 능력과 시간이 모두 부족해서 단순히 화면 송출만 했습니다. 제가 검수하지 않은 Div1F와 Div1G의 풀이를 제대로 이해하지 못해서 잘 설명하지 못한 것도 아쉬웠습니다. 다음에 또 방송을 하게 된다면 방송 준비에 시간을 더 투자해야 할 것 같습니다. 그래도 슬라이드에 사소한 오타가 몇 개 있었던 것을 제외하면 별 문제 없이 진행된 점은 좋았습니다.</p> <h2 id="대회-마무리">대회 마무리</h2> <p>이제 상금 지급, 인건비 지급과 같은 일만 남아서 인건비 계산을 제외하면 제가 할 일은 없는 것 같습니다.</p> <p>대회 운영을 정말 밥 먹듯이 해왔지만, 이번처럼 운영진이 많은 대회에서 제가 중요한 역할을 맡은 건 처음이라 너무 힘들었습니다. 숭고한과는 비교도 안 될 만큼 규모가 큰 UCPC를 이끌어 나가는 UCPC 회장들과 BOJ 연말 대회 핵심 운영진들이 정말 대단하다는 것을 느꼈습니다.</p> <p>이번에 너무 많이 고생해서, SCCC 회장이지만 다음부터는 숭고한 대회 운영은 안 하고 싶습니다. 올해 여름에는 제 공부가 급해서 절대 운영 안 할 생각이고 겨울에는 내년 회장한테 넘기고 도망가는 것이 목표입니다.<br /> <strong>“알고리즘 동아리들이 모여 공부 방법과 내용을 교류하자”</strong> 는 취지에서 만들어진 행사인 만큼 차라리 알고리즘 강의를 시키면 할 텐데, 다른 운영진들은 강의보다 대회를 더 중요하게 생각하는 것 같아 아쉽습니다. 강의 준비보다 대회 개최가 더 쉽다고 생각하는 사람들이 많던데, 대회 개최를 가볍게 생각하지 않았으면 좋겠습니다.</p> <p>고등학생 때 고생했던 것들이 지금은 정말 재미있었던 기억으로 남아있는 걸 생각해보면, 나중에 생각해봤을 때 이것도 나름 재미있던 추억으로 남을지도 모르겠습니다. 심지어 대회 준비 초반에 화났던 일들이 지금은 잘 기억이 나지 않습니다. <strong>하지만</strong> 이번에 힘들었던 기억을 까먹고 다시 숭고한 대회를 운영하는 일은 발생하지 않았으면 좋겠습니다. 제 기억력을 한 번 믿어보겠습니다.</p> <h2 id="마치며">마치며…</h2> <p>고등학교 2학년 때 대회 열어보겠다고 객기부리던 것과 3학년 때 UCPC Call for Tasks에 문제 제출하고 조마조마하며 기다리던 것이 엊그제 같은데, 이제는 문제 출제와 관련된 대부분의 업무를 처리할 수 있을 정도로 성장한 것 같습니다. 3년 전, 수능을 100일 앞둔 시점에 제 첫 대회 개최를 도와준 Ryute님과 UCPC, SPC, SUAPC 등 다양한 대회의 운영 경력을 쌓을 기회를 주신 shiftpsh님을 비롯한 서강대 분들, BOJ 연말 대회마다 저를 불러주신 leejseo님, 그리고 최고의 선배 wookje님께 정말 감사드립니다.</p> <p>중간고사 이후부터는 SCCC 내부 스터디를 진행해야 해서 쉴 틈이 없을 것 같습니다. 소모임 회장을 괜히 한 것 같아 매일 후회하고 있지만, 미래의 저에게는 좋은 추억과 양분이 되리라 생각하며 열심히 하고 있습니다.</p> <p>학점을 포기했다고 떠드는 사람은 대외 활동을 지배하고 있다는 말이 있습니다. 이미 학점은 망해서 대외 활동을 지배해볼까 합니다. 뭔가 한 건 많은데 수상 실적이 부족한 것 같으니 SCPC와 ICPC를 위해 열심히 공부해야겠습니다. 여름방학 끝날 때까지 대회 운영 안 한다는 얘기입니다.</p> <p>끝!</p>JusticeHui서론 3달 동안 준비한 숭고한 연합 알고리즘 대회가 드디어 끝났습니다. 저는 Div.1의 가장 어려운 문제, Div.2의 두 번째로 어려운 문제, Div.3의 가장 어려운 문제를 출제하고, 문제의 선제와 검수를 총괄했습니다. 대회 종료 후 풀이 방송도 담당했습니다. 올해 초에 대회 준비를 시작할 때부터 주변 지인들에게 때려치우고 싶다고 1시간에 한 번씩 징징거렸는데 대회가 끝나고 나니 속이 후련하네요. 운영진에 합류하게 된 과정부터 대회 풀이 방송까지, 여러 가지 이야기를 풀어보도록 하겠습니다.2022 성균관대학교 프로그래밍 경진대회 검수와 상수 커팅 이야기2022-02-27T10:51:00+00:002022-02-27T10:51:00+00:00https://justicehui.github.io/ps/2022/02/27/2022skku<h2 id="서론">서론</h2> <p>2022년 성균관대학교 프로그래밍 경진대회에 검수자로 참여했습니다.<br /> 이번 대회에는 저보다 훨씬 실력이 좋은 분들이 검수자로 함께 참여했습니다. 다른 검수자들이 저보다 훨씬 빠르고 정확하게 풀이 검증을 해주셨기 때문에 저는 상수 최적화를 통한 데이터 강화에 더 집중했습니다. 평소에는 대회 검수 후기를 잘 남기지 않는 편이지만, 이번 검수에서 시도한 상수 최적화 방법들이 인상적이라서 오랜만에 검수 후기를 작성해봅니다.<br /> 캐시 히트, 분기 예측, SIMD를 알고 있으면 글을 읽는데 도움이 될 수 있습니다.</p> <h2 id="boj-24529-이야기-배열---문제-설명">BOJ 24529 이야기 배열 - 문제 설명</h2> <blockquote> <p>3개의 이야기 보따리에 각각 $N$개의 이야기가 있다. 이야기는 길이와 재미있는 정도를 갖고 있다.<br />$3N$의 이야기 중 $N$개의 이야기를 뽑아 나열해서 <strong>재미있는 정도의 합을 최대화</strong>해야 하는데, 이때 $i$번째로 오는 <strong>이야기의 길이는 $D_i$ 이하</strong>가 되어야 한다.<br />$D_i$가 단조 증가할 때($D_i \leq D_{i+1}$), 이야기의 재미있는 정도의 합의 최댓값을 구하자.</p> </blockquote> <p>문제 풀이를 먼저 설명하겠습니다.<br /> 이야기 길이의 상한 조건을 만족하는 임의의 이야기 배열은, 같은 보따리에서 나온 이야기를 길이가 단조 증가하는 형태로 바꿀 수 있습니다. 그러므로 각 보따리에 있는 이야기를 길이 오름차순으로 정렬한 뒤 순서대로 뽑아도 됩니다. 이 아이디어를 이용하면 아래와 같은 점화식을 쉽게 떠올릴 수 있습니다.<br /> $D[n][a][b][c][p] := $ 세 개의 보따리에서 각각 $a, b, c$ 번째 이야기까지 사용해서 $n$개의 이야기를 선택했고, 마지막으로 선택한 보따리가 $p$일 때 재미의 최댓값</p> <p>이 점화식은 $O(N^4)$개의 상태가 있고, 각 상태의 답을 $O(1)$에 계산할 수 있기 때문에 $O(N^4)$에 문제를 해결할 수 있습니다. 이것이 출제자가 의도한 풀이지만, 열심히 최적화를 하면 $O(N^5)$로도 문제를 해결할 수 있습니다.</p> <h2 id="boj-24529-이야기-배열---on5-최적화">BOJ 24529 이야기 배열 - $O(N^5)$ 최적화</h2> <h4 id="시작">시작</h4> <p>가장 기본적인 코드는 다음과 같습니다. <code class="language-plaintext highlighter-rouge">GetDP</code> 함수를 $O(N^4)$번 호출하고, <code class="language-plaintext highlighter-rouge">GetDP</code> 함수는 상태 3개의 답을 $O(N)$에 계산하기 때문에 $O(N^5)$입니다. 이 코드의 실행 시간은 <strong>2400ms</strong> 입니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">L</span><span class="p">[</span><span class="mi">64</span><span class="p">],</span> <span class="n">D</span><span class="p">[</span><span class="mi">64</span><span class="p">][</span><span class="mi">64</span><span class="p">][</span><span class="mi">64</span><span class="p">][</span><span class="mi">64</span><span class="p">][</span><span class="mi">3</span><span class="p">];</span> <span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">A</span><span class="p">[</span><span class="mi">64</span><span class="p">],</span> <span class="n">B</span><span class="p">[</span><span class="mi">64</span><span class="p">],</span> <span class="n">C</span><span class="p">[</span><span class="mi">64</span><span class="p">];</span> <span class="kt">void</span> <span class="nf">GetDP</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">,</span> <span class="kt">int</span> <span class="n">c</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">a</span><span class="p">].</span><span class="n">first</span> <span class="o">&lt;=</span> <span class="n">L</span><span class="p">[</span><span class="n">i</span><span class="p">]){</span> <span class="kt">int</span> <span class="o">&amp;</span><span class="n">now</span> <span class="o">=</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">0</span><span class="p">];</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">a</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">A</span><span class="p">[</span><span class="n">a</span><span class="p">].</span><span class="n">second</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="n">A</span><span class="p">[</span><span class="n">a</span><span class="p">].</span><span class="n">second</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">B</span><span class="p">[</span><span class="n">b</span><span class="p">].</span><span class="n">first</span> <span class="o">&lt;=</span> <span class="n">L</span><span class="p">[</span><span class="n">i</span><span class="p">]){</span> <span class="kt">int</span> <span class="o">&amp;</span><span class="n">now</span> <span class="o">=</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">1</span><span class="p">];</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">b</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">B</span><span class="p">[</span><span class="n">b</span><span class="p">].</span><span class="n">second</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="n">B</span><span class="p">[</span><span class="n">b</span><span class="p">].</span><span class="n">second</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="n">c</span><span class="p">].</span><span class="n">first</span> <span class="o">&lt;=</span> <span class="n">L</span><span class="p">[</span><span class="n">i</span><span class="p">]){</span> <span class="kt">int</span> <span class="o">&amp;</span><span class="n">now</span> <span class="o">=</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">2</span><span class="p">];</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">c</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">C</span><span class="p">[</span><span class="n">c</span><span class="p">].</span><span class="n">second</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">C</span><span class="p">[</span><span class="n">c</span><span class="p">].</span><span class="n">second</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">second</span> <span class="o">&gt;&gt;</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">first</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">B</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">second</span> <span class="o">&gt;&gt;</span> <span class="n">B</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">first</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">second</span> <span class="o">&gt;&gt;</span> <span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">first</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">L</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="n">sort</span><span class="p">(</span><span class="n">A</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">A</span><span class="o">+</span><span class="n">N</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span> <span class="n">sort</span><span class="p">(</span><span class="n">B</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">B</span><span class="o">+</span><span class="n">N</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span> <span class="n">sort</span><span class="p">(</span><span class="n">C</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">C</span><span class="o">+</span><span class="n">N</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span> <span class="n">memset</span><span class="p">(</span><span class="n">D</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="k">sizeof</span> <span class="n">D</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">3</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">D</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">a</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">a</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">b</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">b</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">b</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">c</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">c</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">c</span><span class="o">++</span><span class="p">)</span> <span class="n">GetDP</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">);</span> <span class="p">}</span> <span class="kt">int</span> <span class="n">mx</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">a</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">a</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">b</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">b</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">b</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">c</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">c</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">c</span><span class="o">++</span><span class="p">){</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">d</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">d</span><span class="o">&lt;</span><span class="mi">3</span><span class="p">;</span> <span class="n">d</span><span class="o">++</span><span class="p">)</span> <span class="n">mx</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">mx</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="n">d</span><span class="p">]);</span> <span class="p">}</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">mx</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <h4 id="캐시-히트">캐시 히트</h4> <p>사용하는 메모리의 크기가 커질수록 캐시 미스가 더 많이 발생하기 때문에 DP 테이블의 크기를 줄여야 합니다. <code class="language-plaintext highlighter-rouge">GetDP</code> 함수에서 $D[i]$의 값을 계산할 때 $D[i-1]$만 사용하므로 토글링을 사용해서 DP 테이블의 크기를 $N\cdot N\cdot N\cdot N\cdot 3$에서 $2\cdot N\cdot N\cdot N\cdot 3$으로 줄일 수 있습니다.<br /> <code class="language-plaintext highlighter-rouge">GetDP</code> 함수에서 모든 <code class="language-plaintext highlighter-rouge">i</code>와 <code class="language-plaintext highlighter-rouge">i-1</code> 뒤에 <code class="language-plaintext highlighter-rouge">&amp;1</code>이 붙었으며, 47번째 줄에 <code class="language-plaintext highlighter-rouge">memset(D[i&amp;1], -1, sizeof(D) / 2);</code>이 추가되었습니다. 이 코드의 실행 시간은 <strong>2100ms</strong> 이며, 이전 코드에 비해 300ms 정도 감소했습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">L</span><span class="p">[</span><span class="mi">64</span><span class="p">],</span> <span class="n">D</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">64</span><span class="p">][</span><span class="mi">64</span><span class="p">][</span><span class="mi">64</span><span class="p">][</span><span class="mi">3</span><span class="p">];</span> <span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">A</span><span class="p">[</span><span class="mi">64</span><span class="p">],</span> <span class="n">B</span><span class="p">[</span><span class="mi">64</span><span class="p">],</span> <span class="n">C</span><span class="p">[</span><span class="mi">64</span><span class="p">];</span> <span class="kt">void</span> <span class="nf">GetDP</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">,</span> <span class="kt">int</span> <span class="n">c</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">a</span><span class="p">].</span><span class="n">first</span> <span class="o">&lt;=</span> <span class="n">L</span><span class="p">[</span><span class="n">i</span><span class="p">]){</span> <span class="kt">int</span> <span class="o">&amp;</span><span class="n">now</span> <span class="o">=</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">0</span><span class="p">];</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">a</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">A</span><span class="p">[</span><span class="n">a</span><span class="p">].</span><span class="n">second</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="n">A</span><span class="p">[</span><span class="n">a</span><span class="p">].</span><span class="n">second</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">B</span><span class="p">[</span><span class="n">b</span><span class="p">].</span><span class="n">first</span> <span class="o">&lt;=</span> <span class="n">L</span><span class="p">[</span><span class="n">i</span><span class="p">]){</span> <span class="kt">int</span> <span class="o">&amp;</span><span class="n">now</span> <span class="o">=</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">1</span><span class="p">];</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">b</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">B</span><span class="p">[</span><span class="n">b</span><span class="p">].</span><span class="n">second</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="n">B</span><span class="p">[</span><span class="n">b</span><span class="p">].</span><span class="n">second</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="n">c</span><span class="p">].</span><span class="n">first</span> <span class="o">&lt;=</span> <span class="n">L</span><span class="p">[</span><span class="n">i</span><span class="p">]){</span> <span class="kt">int</span> <span class="o">&amp;</span><span class="n">now</span> <span class="o">=</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">2</span><span class="p">];</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">c</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">C</span><span class="p">[</span><span class="n">c</span><span class="p">].</span><span class="n">second</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">C</span><span class="p">[</span><span class="n">c</span><span class="p">].</span><span class="n">second</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">second</span> <span class="o">&gt;&gt;</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">first</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">B</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">second</span> <span class="o">&gt;&gt;</span> <span class="n">B</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">first</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">second</span> <span class="o">&gt;&gt;</span> <span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">first</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">L</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="n">sort</span><span class="p">(</span><span class="n">A</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">A</span><span class="o">+</span><span class="n">N</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span> <span class="n">sort</span><span class="p">(</span><span class="n">B</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">B</span><span class="o">+</span><span class="n">N</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span> <span class="n">sort</span><span class="p">(</span><span class="n">C</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">C</span><span class="o">+</span><span class="n">N</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span> <span class="n">memset</span><span class="p">(</span><span class="n">D</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="k">sizeof</span> <span class="n">D</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">3</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">D</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="n">memset</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">],</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">D</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">a</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">a</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">b</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">b</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">b</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">c</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">c</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">c</span><span class="o">++</span><span class="p">)</span> <span class="n">GetDP</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">);</span> <span class="p">}</span> <span class="kt">int</span> <span class="n">mx</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">a</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">a</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">b</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">b</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">b</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">c</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">c</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">c</span><span class="o">++</span><span class="p">){</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">d</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">d</span><span class="o">&lt;</span><span class="mi">3</span><span class="p">;</span> <span class="n">d</span><span class="o">++</span><span class="p">)</span> <span class="n">mx</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">mx</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">N</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="n">d</span><span class="p">]);</span> <span class="p">}</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">mx</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <h4 id="분기-예측">분기 예측</h4> <p><code class="language-plaintext highlighter-rouge">GetDP</code> 함수의 각 for문마다 복잡한 if문이 2개씩 있습니다. <code class="language-plaintext highlighter-rouge">-1</code>과 비교하고, 다시 <code class="language-plaintext highlighter-rouge">now</code>와 비교해서 더 큰 값을 <code class="language-plaintext highlighter-rouge">now</code>에 대입하는 것은 매우 복잡합니다.<br /> 현대 CPU는 <strong>분기 예측</strong>이라는 기술을 사용합니다. 이는 조건문이 어떤 곳으로 분기할 것인지 미리 예측해서 계산하는 기술입니다. 하지만 예측에 실패하면 미리 계산한 결과를 폐기해야 하기 때문에 어느정도 손해를 보게 됩니다. BOJ 채점 서버에서 사용하는 Intel Haswell의 경우 분기 예측 실패시 15-20 클럭 정도를 낭비한다고 합니다.<br /> PS는 최악의 경우를 고려해야 하기 때문에 분기 예측 실패가 발생할 여지를 줄여야 합니다. 조건문의 개수를 줄여봅시다.</p> <p>아래 코드는 위에서 본 복잡한 조건문 대신 <code class="language-plaintext highlighter-rouge">max</code> 함수만 2개씩 사용합니다. 이 코드의 실행 시간은 <strong>900ms</strong> 이며, 초기 버전에 비해 1500ms 정도 감소했습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">GetDP</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">,</span> <span class="kt">int</span> <span class="n">c</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">a</span><span class="p">].</span><span class="n">first</span> <span class="o">&lt;=</span> <span class="n">L</span><span class="p">[</span><span class="n">i</span><span class="p">]){</span> <span class="kt">int</span> <span class="n">now</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">a</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">1</span><span class="p">]);</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">2</span><span class="p">]);</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">now</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">now</span> <span class="o">+</span> <span class="n">A</span><span class="p">[</span><span class="n">a</span><span class="p">].</span><span class="n">second</span><span class="p">;</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">B</span><span class="p">[</span><span class="n">b</span><span class="p">].</span><span class="n">first</span> <span class="o">&lt;=</span> <span class="n">L</span><span class="p">[</span><span class="n">i</span><span class="p">]){</span> <span class="kt">int</span> <span class="n">now</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">b</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">0</span><span class="p">]);</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">2</span><span class="p">]);</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">now</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">now</span> <span class="o">+</span> <span class="n">B</span><span class="p">[</span><span class="n">b</span><span class="p">].</span><span class="n">second</span><span class="p">;</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="n">c</span><span class="p">].</span><span class="n">first</span> <span class="o">&lt;=</span> <span class="n">L</span><span class="p">[</span><span class="n">i</span><span class="p">]){</span> <span class="kt">int</span> <span class="n">now</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">c</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="mi">0</span><span class="p">]);</span> <span class="n">now</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="mi">1</span><span class="p">]);</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">now</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">][</span><span class="n">c</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">now</span> <span class="o">+</span> <span class="n">C</span><span class="p">[</span><span class="n">c</span><span class="p">].</span><span class="n">second</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <h4 id="컴파일러-최적화">컴파일러 최적화</h4> <p>혹시 모르니 O3 최적화를 켜고 AVX2 명령어를 사용할 수 있도록 컴파일 옵션을 넣어봅시다.<br /> <code class="language-plaintext highlighter-rouge">-O3</code> 옵션만 넣은 코드의 실행 시간은 여전히 <strong>900ms</strong> 정도지만, <code class="language-plaintext highlighter-rouge">-mavx2</code> 옵션까지 넣은 코드의 실행 시간은 <strong>600ms</strong> 정도입니다. 처음에 작성한 코드에 비해 4배 가까이 빨라졌습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#pragma GCC optimize ("O3") #pragma GCC target ("avx2") #include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="c1">// 이하 생략</span> </code></pre></div></div>JusticeHui서론 2022년 성균관대학교 프로그래밍 경진대회에 검수자로 참여했습니다. 이번 대회에는 저보다 훨씬 실력이 좋은 분들이 검수자로 함께 참여했습니다. 다른 검수자들이 저보다 훨씬 빠르고 정확하게 풀이 검증을 해주셨기 때문에 저는 상수 최적화를 통한 데이터 강화에 더 집중했습니다. 평소에는 대회 검수 후기를 잘 남기지 않는 편이지만, 이번 검수에서 시도한 상수 최적화 방법들이 인상적이라서 오랜만에 검수 후기를 작성해봅니다. 캐시 히트, 분기 예측, SIMD를 알고 있으면 글을 읽는데 도움이 될 수 있습니다.