Jekyll2023-09-24T12:57:49+00:00https://justicehui.github.io/rss/JusticeHui가 PS하는 블로그Let's solve problem with JusticeHui!JusticeHui2023 SCPC 2차예선 풀이2023-08-19T00:00:00+00:002023-08-19T00:00:00+00:00https://justicehui.github.io/review/2023/08/19/scpc-qual-2<h3 id="총평">총평</h3> <p>1, 2, 3, 4번 모두 작년/재작년보다 훨씬 어려워졌습니다. 많은 구현을 요구하는 1번을 풀고 나면 전형적인 문제일지 애드혹일지 감이 잡히지 않아 오만 가지 생각이 다 드는 2번과 3번 문제가 머리를 때리고, 뒤쪽 문제를 읽어보겠다고 4~5번으로 넘어가면 만점자가 한 자리 수인 문제들이 반겨줍니다. 4번과 5번은 만점자가 한 자리 수이고 풀 태스크를 제외한 모든 서브태스크를 긁는 건 쉽기 때문에 별로 문제가 안 되었지만, 3번이 정말… 힘들었습니다. 1차가 쉬웠던 이유가 2차에 어려운 문제를 몰아넣어서 그런 건가? 올해는 오랜만에 3번을 안 풀고도 본선에 진출하는 사람이 나올 것 같기도 합니다.</p> <table> <thead> <tr> <th>문제</th> <th>점수</th> <th>제출 횟수</th> </tr> </thead> <tbody> <tr> <td>1. 타이젠 윷놀이</td> <td>100/100</td> <td>1 (100)</td> </tr> <tr> <td>2. 괄호 문자열</td> <td>200/200</td> <td>2 (0 → 200)</td> </tr> <tr> <td>3. 루머</td> <td>300/300</td> <td>3 (90 → 180 → 300)</td> </tr> <tr> <td>4. 막대기 연결</td> <td>180/400</td> <td>1 (180)</td> </tr> <tr> <td>5. 스파트 아파트 건설</td> <td>60/400</td> <td>1 (60)</td> </tr> <tr> <td>총점</td> <td>840/1400</td> <td>8</td> </tr> </tbody> </table> <h3 id="타이젠-윷놀이">타이젠 윷놀이</h3> <blockquote> <p>말 하나를 이용해 윷놀이를 한다. 윷을 $N$번 던진 결과가 차례대로 주어지고, 이 $N$번의 행동을 $K$번 반복해서 총 $N\times K$번 말을 움직일 때, 말이 몇 바퀴 도는지 구하는 문제<br />$T \leq 87;$ $N,K \times 10^5;$ 백도는 주어지지 않음</p> </blockquote> <p>다음과 같이 윷놀이 판의 각 칸에 번호를 붙입시다. 29는 한 바퀴를 온전히 돌았다는 것을 표시하기 위한 칸입니다.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>15 - 14 - 13 - 12 - 11 - (10) | \ / | 16 24 25 9 | \ / | 17 23 26 8 | (22) | 18 27 21 7 | / \ | 19 28 20 6 | / \ | (0) - 1 - 2 - 3 - 4 - (5) ㄴ 29 </code></pre></div></div> <p>5번, 10번, 22번 칸은 그냥 지나가는 것과 멈추는 것을 다르게 취급해야 하므로 두 개의 점으로 분리해서 생각해야 합니다. 또한, 0번 칸은 시작점의 역할과 도착점의 한 칸 전의 역할을 모두 수행하기 때문에 0번 칸도 두 개의 점으로 분리해서 생각해야 합니다. 따라서 총 34개의 정점을 이용해 윷놀이 판을 관리합니다.</p> <p>$v$번 정점의 다음 칸을 $\text{next}(v)$는 정점 개수에 비례하는 시간에 전처리할 수 있고, 이를 이용하면 $v$에서 $k (1 \leq k \leq 5)$칸 이동한 결과인 $\text{move}(v, k)$도 $5 \times$ (정점 개수) 정도에 전처리할 수 있습니다.</p> <p>실제 문제의 정답을 구하는 것은, 각 칸에서 $N$번 이동했을 때 도착점에 가는 횟수와 종료 상태를 구하면 됩니다. 유효한 정점은 34개로 상수 개이므로 $O(N)$ 시간에 모두 전처리할 수 있고, $K$번 반복해서 이동한 결과는 전처리한 정보를 이용해 $O(K)$ 시간에 구할 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">ID</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">return</span> <span class="n">i</span> <span class="o">*</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">j</span><span class="p">;</span> <span class="p">}</span> <span class="kt">bool</span> <span class="nf">IsStart</span><span class="p">(</span><span class="kt">int</span> <span class="n">v</span><span class="p">){</span> <span class="k">return</span> <span class="n">v</span> <span class="o">!=</span> <span class="n">ID</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span><span class="mi">0</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">v</span> <span class="o">!=</span> <span class="n">ID</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">0</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">v</span> <span class="o">!=</span> <span class="n">ID</span><span class="p">(</span><span class="mi">22</span><span class="p">,</span><span class="mi">0</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">Next</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="p">}</span> <span class="kt">void</span> <span class="nf">Init</span><span class="p">(){</span> <span class="n">memset</span><span class="p">(</span><span class="n">Next</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">Next</span><span class="p">);</span> <span class="n">S</span> <span class="o">=</span> <span class="n">ID</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">T</span> <span class="o">=</span> <span class="n">ID</span><span class="p">(</span><span class="mi">29</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">19</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">Next</span><span class="p">[</span><span class="n">ID</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="o">=</span> <span class="n">ID</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="mi">0</span><span class="p">);</span> <span class="n">Next</span><span class="p">[</span><span class="n">ID</span><span class="p">(</span><span class="mi">19</span><span class="p">,</span><span class="mi">0</span><span class="p">)]</span> <span class="o">=</span> <span class="n">ID</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span> <span class="n">Next</span><span class="p">[</span><span class="n">ID</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span><span class="mi">1</span><span class="p">)]</span> <span class="o">=</span> <span class="n">ID</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span> <span class="n">Next</span><span class="p">[</span><span class="n">ID</span><span class="p">(</span><span class="mi">24</span><span class="p">,</span><span class="mi">0</span><span class="p">)]</span> <span class="o">=</span> <span class="n">ID</span><span class="p">(</span><span class="mi">15</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">20</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">24</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">Next</span><span class="p">[</span><span class="n">ID</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="o">=</span> <span class="n">ID</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="mi">0</span><span class="p">);</span> <span class="n">Next</span><span class="p">[</span><span class="n">ID</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">1</span><span class="p">)]</span> <span class="o">=</span> <span class="n">ID</span><span class="p">(</span><span class="mi">25</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span> <span class="n">Next</span><span class="p">[</span><span class="n">ID</span><span class="p">(</span><span class="mi">25</span><span class="p">,</span><span class="mi">0</span><span class="p">)]</span> <span class="o">=</span> <span class="n">ID</span><span class="p">(</span><span class="mi">26</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span> <span class="n">Next</span><span class="p">[</span><span class="n">ID</span><span class="p">(</span><span class="mi">26</span><span class="p">,</span><span class="mi">0</span><span class="p">)]</span> <span class="o">=</span> <span class="n">ID</span><span class="p">(</span><span class="mi">22</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span> <span class="n">Next</span><span class="p">[</span><span class="n">ID</span><span class="p">(</span><span class="mi">22</span><span class="p">,</span><span class="mi">1</span><span class="p">)]</span> <span class="o">=</span> <span class="n">ID</span><span class="p">(</span><span class="mi">27</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span> <span class="n">Next</span><span class="p">[</span><span class="n">ID</span><span class="p">(</span><span class="mi">27</span><span class="p">,</span><span class="mi">0</span><span class="p">)]</span> <span class="o">=</span> <span class="n">ID</span><span class="p">(</span><span class="mi">28</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span> <span class="n">Next</span><span class="p">[</span><span class="n">ID</span><span class="p">(</span><span class="mi">28</span><span class="p">,</span><span class="mi">0</span><span class="p">)]</span> <span class="o">=</span> <span class="n">ID</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span> <span class="n">Next</span><span class="p">[</span><span class="n">ID</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">)]</span> <span class="o">=</span> <span class="n">ID</span><span class="p">(</span><span class="mi">29</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span> <span class="n">Next</span><span class="p">[</span><span class="n">ID</span><span class="p">(</span><span class="mi">29</span><span class="p">,</span><span class="mi">0</span><span class="p">)]</span> <span class="o">=</span> <span class="n">ID</span><span class="p">(</span><span class="mi">29</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">61</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">5</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="n">v</span> <span class="o">=</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">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">j</span><span class="p">;</span> <span class="n">k</span><span class="o">++</span><span class="p">)</span> <span class="n">v</span> <span class="o">=</span> <span class="n">Next</span><span class="p">[</span><span class="n">v</span><span class="p">];</span> <span class="n">Go</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">v</span> <span class="o">^</span> <span class="o">!</span><span class="n">IsStart</span><span class="p">(</span><span class="n">v</span><span class="p">);</span> <span class="p">}</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">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="kt">int</span> <span class="n">move</span><span class="p">[</span><span class="mi">61</span><span class="p">],</span> <span class="n">get</span><span class="p">[</span><span class="mi">61</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">61</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">IsStart</span><span class="p">(</span><span class="n">i</span><span class="p">))</span> <span class="k">continue</span><span class="p">;</span> <span class="kt">int</span> <span class="n">now</span> <span class="o">=</span> <span class="n">i</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">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">N</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">Go</span><span class="p">[</span><span class="n">now</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="o">-</span><span class="mi">1</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="n">T</span><span class="p">)</span> <span class="n">cnt</span><span class="o">++</span><span class="p">,</span> <span class="n">now</span> <span class="o">=</span> <span class="n">S</span><span class="p">;</span> <span class="p">}</span> <span class="n">move</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">now</span><span class="p">;</span> <span class="n">get</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">cnt</span><span class="p">;</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="n">S</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">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">res</span> <span class="o">+=</span> <span class="n">get</span><span class="p">[</span><span class="n">now</span><span class="p">],</span> <span class="n">now</span> <span class="o">=</span> <span class="n">move</span><span class="p">[</span><span class="n">now</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> </code></pre></div></div> <h3 id="괄호-문자열">괄호 문자열</h3> <blockquote> <p>소괄호와 중괄호로 구성된 괄호 문자열이 주어지면, 올바른 괄호 문자열인 부분 문자열의 개수를 구하는 문제<br />$N \leq 10^6;$ $\sum N \leq 42 \times 10^6$</p> </blockquote> <p>처음 문제를 보면 별의별 생각이 다 듭니다. 처음에는 끝점을 고정한 다음, 문자열의 prefix를 쪼갤 수 없는 괄호 문자열들로 분할해서 가능한 시작점의 개수를 세는 방식으로 접근했지만, 별다른 소득을 얻지 못했습니다. 구체적으로, 문자열의 분할을 incremental하게 관리할 방법도 잘 안 보였고, 관리할 수 있다고 하더라도 선형 시간에 하기는 어려울 것 같아서 포기했습니다.</p> <p>문자열을 maximal한 올바른 괄호 문자열들로 분할하면, 각 그룹을 독립적으로 생각해도 된다는 것을 알 수 있습니다. 서로 다른 두 그룹에 모두 걸쳐 있는 올바른 괄호 문자열이 있다면 maximal한 문자열들로 분할한 것이 아니기 때문입니다. 따라서 스택을 이용해 maximal한 올바른 괄호 문자열로 분리한 다음, 각각의 올바른 괄호 문자열에서의 답을 선형 시간에 구하면 문제를 해결할 수 있습니다. 분할된 각 문자열은 <strong>올바른</strong> 괄호 문자열이기 때문에 소괄호와 중괄호의 구분을 신경 쓰지 않아도 되므로 구현이 쉬워집니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span> <span class="nf">Match</span><span class="p">(</span><span class="kt">char</span> <span class="n">a</span><span class="p">,</span> <span class="kt">char</span> <span class="n">b</span><span class="p">){</span> <span class="k">return</span> <span class="n">a</span> <span class="o">==</span> <span class="sc">'('</span> <span class="o">&amp;&amp;</span> <span class="n">b</span> <span class="o">==</span> <span class="sc">')'</span> <span class="o">||</span> <span class="n">a</span> <span class="o">==</span> <span class="sc">'{'</span> <span class="o">&amp;&amp;</span> <span class="n">b</span> <span class="o">==</span> <span class="sc">'}'</span><span class="p">;</span> <span class="p">}</span> <span class="kt">bool</span> <span class="nf">Open</span><span class="p">(</span><span class="kt">char</span> <span class="n">c</span><span class="p">){</span> <span class="k">return</span> <span class="n">c</span> <span class="o">==</span> <span class="sc">'('</span> <span class="o">||</span> <span class="n">c</span> <span class="o">==</span> <span class="sc">'{'</span><span class="p">;</span> <span class="p">}</span> <span class="n">ll</span> <span class="nf">Go</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="n">ll</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="n">ll</span><span class="o">&gt;</span> <span class="n">val</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="k">auto</span> <span class="n">c</span> <span class="o">:</span> <span class="n">s</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">Open</span><span class="p">(</span><span class="n">c</span><span class="p">))</span> <span class="n">val</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="k">else</span><span class="p">{</span> <span class="n">res</span> <span class="o">+=</span> <span class="n">val</span><span class="p">.</span><span class="n">back</span><span class="p">()</span> <span class="o">*</span> <span class="p">(</span><span class="n">val</span><span class="p">.</span><span class="n">back</span><span class="p">()</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span> <span class="n">val</span><span class="p">.</span><span class="n">pop_back</span><span class="p">();</span> <span class="n">val</span><span class="p">.</span><span class="n">back</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="n">res</span> <span class="o">+=</span> <span class="n">val</span><span class="p">.</span><span class="n">back</span><span class="p">()</span> <span class="o">*</span> <span class="p">(</span><span class="n">val</span><span class="p">.</span><span class="n">back</span><span class="p">()</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</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">vector</span><span class="o">&lt;</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">Tokenizer</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="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">vector</span><span class="o">&lt;</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">res</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">idx</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">stk</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">if</span><span class="p">(</span><span class="n">Open</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">stk</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">else</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">stk</span><span class="p">.</span><span class="n">empty</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">Match</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">stk</span><span class="p">.</span><span class="n">back</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">idx</span><span class="p">[</span><span class="n">stk</span><span class="p">.</span><span class="n">back</span><span class="p">()]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span> <span class="n">idx</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">stk</span><span class="p">.</span><span class="n">back</span><span class="p">();</span> <span class="n">stk</span><span class="p">.</span><span class="n">pop_back</span><span class="p">();</span> <span class="p">}</span> <span class="k">else</span> <span class="n">stk</span><span class="p">.</span><span class="n">clear</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">if</span><span class="p">(</span><span class="n">idx</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">j</span><span class="o">++</span><span class="p">;</span> <span class="k">continue</span><span class="p">;</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">idx</span><span class="p">[</span><span class="n">j</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">j</span><span class="o">++</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">s</span><span class="p">.</span><span class="n">substr</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="n">i</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="n">ll</span> <span class="nf">Solve</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="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="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">Tokenizer</span><span class="p">(</span><span class="n">s</span><span class="p">))</span> <span class="n">res</span> <span class="o">+=</span> <span class="n">Go</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> <span class="k">return</span> <span class="n">res</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <h3 id="루머">루머</h3> <blockquote> <p>$N$명의 사람이 일렬로 서있다. 시간 $t$에 $i$번째 사람과 인접한 사람 중 $A_i$명 이상이 루머를 믿고 있으면, $t+1$ 이후부터 $i$번째 사람도 루머를 믿는다. $t = 0$인 시점부터 루머를 믿는 사람을 최대 $M$명 선택할 수 있을 때, $T$ 시간이 지난 후 루머를 믿는 사람의 최댓값을 구하는 문제<br />$M,T \leq N \leq 5\,000;$ $1 \leq A_i \leq 2$</p> </blockquote> <p>이 문제도 다양한 시도를 했습니다. 처음에는 그래프로 접근해서 위상 정렬 같은 느낌으로 풀려고 했지만 실패했습니다. 그다음에는 $C(i, j) :=$ $[i,j]$ 구간을 활성화하는 데 필요한 최소 선택 횟수로 정의한 테이블을 어떻게든 계산한 다음, $D(i, k) := $ $[1, i]$ 구간을 $k$명으로 시작해서 활성화할 수 있는 최대 칸 개수 같은 것을 계산하려고 했고, 이 방법으로도 아무 소득도 얻지 못했습니다.</p> <p>그다음 접근은 효과가 있었는데, $D(i, j) :=$ $i$명을 선택했고, 그중 마지막으로 선택한 사람이 $j$일 때 활성화되는 칸 개수의 최댓값으로 정의해서 계산하는 것이었습니다. 편의상 $L_i,R_i$를 $i$의 왼쪽/오른쪽에 있는 가장 가까운 2번 칸의 인덱스, $S_i = \max(i-t,L_i+1)$, $E_i=\min(i+t, R_i-1)$으로 정의합시다. $D(i, j)$는 항상 정확히 $E_i$까지 활성화하기 때문에, 이후에 선택하는 위치에 따라 2번 칸의 활성화 여부를 어렵지 않게 추적할 수 있습니다. 구체적으로, $D(i+1,k) \leftarrow D(i,j)$ 형태의 상태 전이는 다음과 같이 8가지로 나눠서 계산할 수 있습니다.</p> <ol> <li>$j$와 $k$의 담당 구간이 겹치지 않는 경우 ($j+2t &lt; k \leq N$) <ul> <li>$D(i+1,k) \leftarrow D(i,j) + E_k - S_k + 1$</li> </ul> </li> <li>$j$와 $k$의 구간이 겹치지만 서로의 위치를 포함하진 않는 경우 ($j+t &lt; k \leq j+2t$) <ol> <li>$j$의 오른쪽, $k$의 왼쪽에 2번 칸이 없는 경우 ($R_j = \infty \text{ and } L_k = -\infty$) <ul> <li>$D(i+1,k) \leftarrow D(i,j) + E_k - E_j$</li> </ul> </li> <li>2번 칸이 존재하지만, 두 구간의 교집합이 아닌 위치에 하나 이상 존재하는 경우 ($R_j &lt; k-t \text{ or } j+t &lt; L_k$) <ul> <li>$D(i+1,k) \leftarrow D(i,j) + E_k - \max(S_k, E_j+1) + 1$</li> </ul> </li> <li>1개의 2번 칸이 두 구간의 교집합에 위치하는 경우 ($R_j = L_k$) <ul> <li>$D(i+1,k) \leftarrow D(i,j) + E_k - E_j$</li> </ul> </li> <li>2개 이상의 2번 칸이 두 구간의 교집합에 위치하는 경우 <ul> <li>$D(i+1,k) \leftarrow D(i,j) + E_k - S_k + 1$</li> </ul> </li> </ol> </li> <li>$j$와 $k$의 구간이 서로의 위치를 포함하는 경우 ($j &lt; k \leq j+t$) <ol> <li>$j$와 $k$ 사이에 2번 칸이 없는 경우 ($k \leq R_j \text{ or } L_k \leq j$) <ul> <li>$D(i+1,k) \leftarrow D(i,j) + E_k - E_j$</li> </ul> </li> <li>$j$와 $k$ 사이에 2번 칸이 정확히 1개 있는 경우 ($R_j = L_k$) <ul> <li>$D(i+1,k) \leftarrow D(i,j) + E_k - E_j$</li> </ul> </li> <li>$j$와 $k$ 사이에 2번 칸이 2개 이상 있는 경우 <ul> <li>$D(i+1,k) \leftarrow D(i,j) + E_k - S_k + 1$</li> </ul> </li> </ol> </li> </ol> <p>이 상태 전이를 naive하게 구현하면 $O(N^3)$ 시간에 문제를 풀어 90점을 받을 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">inline</span> <span class="kt">int</span> <span class="nf">GetL</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span> <span class="k">return</span> <span class="n">max</span><span class="p">(</span><span class="n">L</span><span class="p">[</span><span class="n">x</span><span class="p">]</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">T</span><span class="p">);</span> <span class="p">}</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="nf">GetR</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span> <span class="k">return</span> <span class="n">min</span><span class="p">(</span><span class="n">R</span><span class="p">[</span><span class="n">x</span><span class="p">]</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">T</span><span class="p">);</span> <span class="p">}</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="nf">Only</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span> <span class="k">return</span> <span class="n">GetR</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">-</span> <span class="n">GetL</span><span class="p">(</span><span class="n">x</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">Init</span><span class="p">(){</span> <span class="n">fill</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="n">L</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="mi">0</span><span class="p">);</span> <span class="n">fill</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="n">R</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">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="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">&gt;=</span><span class="n">max</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="n">i</span><span class="o">-</span><span class="n">T</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">A</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</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="o">=</span> <span class="n">j</span><span class="p">;</span> <span class="k">break</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="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">max</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="n">i</span><span class="o">+</span><span class="n">T</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">A</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="mi">2</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">j</span><span class="p">;</span> <span class="k">break</span><span class="p">;</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">cin</span> <span class="o">&gt;&gt;</span> <span class="n">M</span> <span class="o">&gt;&gt;</span> <span class="n">T</span><span class="p">;</span> <span class="n">Init</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">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">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">nINF</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">D</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">=</span> <span class="n">Only</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">M</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">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="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">k</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="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="c1">// case 1. no intersect (j+t &lt; k-t)</span> <span class="k">if</span><span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="n">T</span> <span class="o">&lt;</span> <span class="n">k</span> <span class="o">-</span> <span class="n">T</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">k</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="o">+</span><span class="mi">1</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">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">+</span> <span class="n">Only</span><span class="p">(</span><span class="n">k</span><span class="p">));</span> <span class="c1">// case 2. intersect, but not contain</span> <span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="n">T</span> <span class="o">&lt;</span> <span class="n">k</span><span class="p">){</span> <span class="c1">// case 2-1. no two</span> <span class="k">if</span><span class="p">(</span><span class="n">R</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="n">N</span><span class="o">+</span><span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="n">L</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</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">k</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="o">+</span><span class="mi">1</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">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">+</span> <span class="n">GetR</span><span class="p">(</span><span class="n">k</span><span class="p">)</span> <span class="o">-</span> <span class="n">GetR</span><span class="p">(</span><span class="n">j</span><span class="p">));</span> <span class="c1">// case 2-2. exist two, but outside</span> <span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">R</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="n">N</span><span class="o">+</span><span class="mi">1</span> <span class="o">||</span> <span class="n">L</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">R</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">k</span><span class="o">-</span><span class="n">T</span> <span class="o">||</span> <span class="n">j</span><span class="o">+</span><span class="n">T</span> <span class="o">&lt;</span> <span class="n">L</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">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">=</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="o">+</span><span class="mi">1</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">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">+</span> <span class="n">GetR</span><span class="p">(</span><span class="n">k</span><span class="p">)</span> <span class="o">-</span> <span class="n">max</span><span class="p">(</span><span class="n">GetL</span><span class="p">(</span><span class="n">k</span><span class="p">),</span> <span class="n">GetR</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="o">+</span> <span class="mi">1</span><span class="p">);</span> <span class="c1">// case 2-3. exist only one two, inside</span> <span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">R</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="n">L</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">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">=</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="o">+</span><span class="mi">1</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">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">+</span> <span class="n">GetR</span><span class="p">(</span><span class="n">k</span><span class="p">)</span> <span class="o">-</span> <span class="n">GetR</span><span class="p">(</span><span class="n">j</span><span class="p">));</span> <span class="c1">// case 2-4. exist at least two twos</span> <span class="k">else</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="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="o">+</span><span class="mi">1</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">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">+</span> <span class="n">Only</span><span class="p">(</span><span class="n">k</span><span class="p">));</span> <span class="p">}</span> <span class="c1">// case 3. intersect, and contain</span> <span class="k">else</span><span class="p">{</span> <span class="c1">// case 3-1. not between</span> <span class="k">if</span><span class="p">(</span><span class="n">k</span> <span class="o">&lt;=</span> <span class="n">R</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">||</span> <span class="n">L</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">&lt;=</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="o">+</span><span class="mi">1</span><span class="p">][</span><span class="n">k</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="o">+</span><span class="mi">1</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">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">+</span> <span class="n">GetR</span><span class="p">(</span><span class="n">k</span><span class="p">)</span> <span class="o">-</span> <span class="n">GetR</span><span class="p">(</span><span class="n">j</span><span class="p">));</span> <span class="c1">// case 3-2. exist only one two, inside</span> <span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">R</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="n">L</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">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">=</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="o">+</span><span class="mi">1</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">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">+</span> <span class="n">GetR</span><span class="p">(</span><span class="n">k</span><span class="p">)</span> <span class="o">-</span> <span class="n">GetR</span><span class="p">(</span><span class="n">j</span><span class="p">));</span> <span class="c1">// case 3-3. exist at least two twos</span> <span class="k">else</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="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="o">+</span><span class="mi">1</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">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">+</span> <span class="n">Only</span><span class="p">(</span><span class="n">k</span><span class="p">));</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="o">*</span><span class="n">max_element</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">M</span><span class="p">]</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">M</span><span class="p">]</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">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <p>이제 이 풀이를 $O(N^2 \log N)$, 더 나아가 $O(N^2)$으로 최적화시켜 봅시다. $O(N^3)$보다 빠르게 풀 때는 $D(i,j)$의 값을 $D(i+1,k)$로 뿌려주는 방식이 아닌, $D(i, k)$의 값을 계산할 때 $D(i-1, j)$의 값을 가져오는 방식으로 구현하는 것이 편합니다.</p> <p>각 $k$마다 위에서 다룬 8가지 경우를 이루는 $j$들이 구간을 이룬다는 것은 직관적으로 유추할 수 있습니다. 사실 증명은 못 했고, $N \leq 16$인 모든 데이터에서 <code class="language-plaintext highlighter-rouge">assert</code>를 이용해 구간을 이룬다는 것을 확인했습니다. 앞으로 언급하는 구간에 대한 모든 내용은 이런 방식으로 증명(?)했음을 미리 밝힙니다. 아무튼 각 경우마다 고려해야 하는 $j$들이 구간을 이룬다고 믿고, 세그먼트 트리를 이용해 점화식을 계산하면 $O(N^2 \log N)$ 시간에 문제를 해결해 180점을 받을 수 있습니다.</p> <p>하지만 8가지 경우를 모두 고려하는 것은 귀찮고 세그먼트 트리를 8개씩 들고 다니는 것도 힘들기 때문에 저는 다음과 같이 케이스를 5가지로 줄였고, 이렇게 해도 각 경우에서 고려하는 $j$가 구간을 이룬다는 것을 확인했습니다.</p> <ol> <li>$j+2t &lt; k \leq N$. 즉, $1 \leq j &lt; k-2t$ <ul> <li>$D(i,k) \leftarrow D(i-1,j) + E_k - S_k + 1$</li> </ul> </li> <li>$j+t &lt; k \leq 2+2t$. 즉, $k-2t \leq j &lt; k-t$ <ol> <li>2번 칸이 교집합에 정확히 1개 존재하는 경우. 즉, $R_j = L_k$ <ul> <li>$D(i, k) \leftarrow D(i-1, j) + E_k - E_j$</li> </ul> </li> <li>그렇지 않은 경우. 즉, $R_j \neq L_k$ <ul> <li>$D(i,k) \leftarrow D(i-1,j) + E(k) - \max(S_k, E_j+1) + 1$</li> </ul> </li> </ol> </li> <li>$j &lt; k \leq j+t$. 즉, $k-t \leq j &lt; k$ <ol> <li>$j$와 $k$ 사이에 2개 이상의 2번 칸이 존재하는 경우. 즉, $R_j &lt; L_k$ <ul> <li>$D(i,k) \leftarrow D(i-1,j) + E_k - S_k + 1$</li> </ul> </li> <li>그렇지 않은 경우. 즉, $R_j \geq L_k$ <ul> <li>$D(i,k) \leftarrow D(i-1,j) + E_k - E_j$</li> </ul> </li> </ol> </li> </ol> <p>여기까지 오면 연산의 종류가 2가지밖에 없다는 사실을 알 수 있습니다. 세그먼트 트리를 사용하는 $O(N^2 \log N)$ 풀이를 $O(N^2)$으로 줄이기 위해서는 세그먼트 트리 대신 슬라이딩 윈도우로 RMQ를 처리하거나, 아니면 기상천외한 아이디어를 이용해 새로운 풀이를 만들어 내는 방법밖에 없습니다. 후자였다면 30명 이상 풀었을 리가 없기 때문에 제 감을 믿고 전자의 방식으로 접근하기 시작했습니다.</p> <p>위에서 나눈 5가지 경우를 이용해 $k$마다 각 $j$가 두 가지 연산 방식 중 어떤 것으로 $D(i, k)$에 반영되는지 표시했더니 놀랍게도 두 연산을 수행하는 구간이 나뉘어 있다는 것을 확인했고, 심지어 구간의 시작점과 끝점에 단조성이 있음을 함께 확인했습니다. 따라서 세그먼트 트리 대신 덱을 이용해서 RMQ를 처리할 수 있고, 시간 복잡도는 $O(N^2)$이 되어서 300점을 받을 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><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">T</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="mi">5050</span><span class="p">],</span> <span class="n">L</span><span class="p">[</span><span class="mi">5050</span><span class="p">],</span> <span class="n">R</span><span class="p">[</span><span class="mi">5050</span><span class="p">],</span> <span class="n">D</span><span class="p">[</span><span class="mi">5050</span><span class="p">][</span><span class="mi">5050</span><span class="p">];</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="nf">GetL</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span> <span class="k">return</span> <span class="n">max</span><span class="p">(</span><span class="n">L</span><span class="p">[</span><span class="n">x</span><span class="p">]</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">T</span><span class="p">);</span> <span class="p">}</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="nf">GetR</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span> <span class="k">return</span> <span class="n">min</span><span class="p">(</span><span class="n">R</span><span class="p">[</span><span class="n">x</span><span class="p">]</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">T</span><span class="p">);</span> <span class="p">}</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="nf">Only</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span> <span class="k">return</span> <span class="n">GetR</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">-</span> <span class="n">GetL</span><span class="p">(</span><span class="n">x</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">int</span> <span class="n">Type</span><span class="p">[</span><span class="mi">5050</span><span class="p">][</span><span class="mi">5050</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">Interval</span><span class="p">[</span><span class="mi">5050</span><span class="p">];</span> <span class="kt">void</span> <span class="nf">Init</span><span class="p">(){</span> <span class="n">fill</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="n">L</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="mi">0</span><span class="p">);</span> <span class="n">fill</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="n">R</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">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="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">&gt;=</span><span class="n">max</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="n">i</span><span class="o">-</span><span class="n">T</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">A</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</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="o">=</span> <span class="n">j</span><span class="p">;</span> <span class="k">break</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="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">min</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="n">i</span><span class="o">+</span><span class="n">T</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">A</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="mi">2</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">j</span><span class="p">;</span> <span class="k">break</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">k</span><span class="o">=</span><span class="mi">1</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="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">k</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="mi">1</span> <span class="o">&lt;=</span> <span class="n">j</span> <span class="o">&amp;&amp;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">k</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">T</span><span class="p">)</span> <span class="n">Type</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="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">k</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">T</span> <span class="o">&lt;=</span> <span class="n">j</span> <span class="o">&amp;&amp;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">k</span> <span class="o">-</span> <span class="n">T</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">R</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="n">L</span><span class="p">[</span><span class="n">k</span><span class="p">])</span> <span class="n">Type</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="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">GetL</span><span class="p">(</span><span class="n">k</span><span class="p">)</span> <span class="o">&gt;</span> <span class="n">GetR</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="n">Type</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="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">else</span> <span class="n">Type</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="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="p">}</span> <span class="k">else</span><span class="p">{</span> <span class="k">if</span><span class="p">(</span><span class="n">R</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">L</span><span class="p">[</span><span class="n">k</span><span class="p">])</span> <span class="n">Type</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="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">else</span> <span class="n">Type</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="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="n">Interval</span><span class="p">[</span><span class="n">k</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">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">k</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">k</span> <span class="o">&amp;&amp;</span> <span class="n">Type</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="o">==</span> <span class="n">Type</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="n">j</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">Interval</span><span class="p">[</span><span class="n">k</span><span class="p">].</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">Type</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="o">-</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="mi">1</span><span class="p">);</span> <span class="p">}</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">cin</span> <span class="o">&gt;&gt;</span> <span class="n">M</span> <span class="o">&gt;&gt;</span> <span class="n">T</span><span class="p">;</span> <span class="n">Init</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">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">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="mh">0xc0c0c0c0</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">D</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">=</span> <span class="n">Only</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">2</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="c1">// type 0: D[i-1][j] + GetR(k) - GetL(k) + 1</span> <span class="c1">// type 1: D[i-1][j] - GetR(j) + GetR(k)</span> <span class="n">deque</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">Q</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span> <span class="k">auto</span> <span class="n">f</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">type</span><span class="p">,</span> <span class="kt">int</span> <span class="n">v</span><span class="p">){</span> <span class="k">return</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">v</span><span class="p">]</span> <span class="o">-</span> <span class="p">(</span><span class="n">type</span> <span class="o">?</span> <span class="n">GetR</span><span class="p">(</span><span class="n">v</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">auto</span> <span class="n">g</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">type</span><span class="p">,</span> <span class="kt">int</span> <span class="n">k</span><span class="p">){</span> <span class="k">return</span> <span class="n">Q</span><span class="p">[</span><span class="n">type</span><span class="p">].</span><span class="n">front</span><span class="p">().</span><span class="n">first</span> <span class="o">+</span> <span class="p">(</span><span class="n">type</span> <span class="o">?</span> <span class="n">GetR</span><span class="p">(</span><span class="n">k</span><span class="p">)</span> <span class="o">:</span> <span class="n">Only</span><span class="p">(</span><span class="n">k</span><span class="p">));</span> <span class="p">};</span> <span class="kt">int</span> <span class="n">lst</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</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">k</span><span class="o">=</span><span class="mi">1</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="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="p">[</span><span class="n">type</span><span class="p">,</span><span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">]</span> <span class="o">:</span> <span class="n">Interval</span><span class="p">[</span><span class="n">k</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">type</span><span class="p">].</span><span class="n">empty</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">Q</span><span class="p">[</span><span class="n">type</span><span class="p">].</span><span class="n">front</span><span class="p">().</span><span class="n">second</span> <span class="o">&lt;</span> <span class="n">l</span><span class="p">)</span> <span class="n">Q</span><span class="p">[</span><span class="n">type</span><span class="p">].</span><span class="n">pop_front</span><span class="p">();</span> <span class="k">for</span><span class="p">(;</span> <span class="n">lst</span><span class="p">[</span><span class="n">type</span><span class="p">]</span><span class="o">&lt;=</span><span class="n">r</span><span class="p">;</span> <span class="n">lst</span><span class="p">[</span><span class="n">type</span><span class="p">]</span><span class="o">++</span><span class="p">){</span> <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">lst</span><span class="p">[</span><span class="n">type</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">type</span><span class="p">].</span><span class="n">empty</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">Q</span><span class="p">[</span><span class="n">type</span><span class="p">].</span><span class="n">back</span><span class="p">().</span><span class="n">first</span> <span class="o">&lt;=</span> <span class="n">f</span><span class="p">(</span><span class="n">type</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">type</span><span class="p">].</span><span class="n">pop_back</span><span class="p">();</span> <span class="n">Q</span><span class="p">[</span><span class="n">type</span><span class="p">].</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">f</span><span class="p">(</span><span class="n">type</span><span class="p">,</span> <span class="n">v</span><span class="p">),</span> <span class="n">v</span><span class="p">);</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">k</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">k</span><span class="p">],</span> <span class="n">g</span><span class="p">(</span><span class="n">type</span><span class="p">,</span> <span class="n">k</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="o">*</span><span class="n">max_element</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">M</span><span class="p">]</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">M</span><span class="p">]</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">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <h3 id="막대기-연결">막대기 연결</h3> <blockquote> <p>2차원 좌표 평면에 $N$개의 점 $(X_i,Y_i)$가 주어진다. 쿼리로 $l,r$이 주어지면 $l \leq a &lt; b \leq r$를 만족하는 $(X_b-X_a) \times (Y_a+Y_b)$의 최솟값을 구하는 문제<br />$N,Q \leq 10^5;$ $1 \leq X_i,Y_i \leq 10^9;$ $X_{i-1} &lt; X_i$</p> </blockquote> <p>전혀 모르겠어서 풀 태스크 바로 아래 단계인 $N,Q \leq 3\,000$인 부분 문제를 풀었습니다. DP와 비슷한 느낌으로 $O(N^2)$ 시간에 모든 쿼리에 대한 답을 전처리하면, 각 쿼리에 대한 답을 상수 시간에 구할 수 있습니다. 자세한 방법은 글로 설명하는 것보다는 코드를 보는 것이 좋을 것 같습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><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">X</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&gt;&gt;</span> <span class="n">H</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="n">cin</span> <span class="o">&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">i</span><span class="o">&lt;=</span><span class="n">Q</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="o">&gt;&gt;</span> <span class="n">R</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="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">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="p">(</span><span class="n">X</span><span class="p">[</span><span class="n">j</span><span class="p">]</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="o">*</span> <span class="p">(</span><span class="n">H</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">H</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">d</span><span class="o">=</span><span class="mi">2</span><span class="p">;</span> <span class="n">d</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">d</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">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="n">d</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">i</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">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">min</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="o">+</span><span class="mi">1</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="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">Q</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">D</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">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="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <h3 id="스마트-아파트-건설">스마트 아파트 건설</h3> <blockquote> <p>간선으로 연결된 두 정점의 가중치 합이 $K$ 이하가 되도록 정점에 $1$부터 $N$까지의 가중치를 정확히 한 번씩 배정하는 문제<br />$T \leq 610;$ $N \leq 20$</p> </blockquote> <p>이 문제도 전혀 모르겠어서 풀 태스크 바로 아래 단계인 $N \leq 8$인 부분 문제를 풀었습니다. $O(N^2 \times N!)$ 시간에 브루트포스를 하면 됩니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><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="o">&gt;&gt;</span> <span class="n">M</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="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">E</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="k">auto</span> <span class="o">&amp;</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="o">:</span> <span class="n">E</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">u</span> <span class="o">&gt;&gt;</span> <span class="n">v</span><span class="p">,</span> <span class="n">u</span><span class="o">--</span><span class="p">,</span> <span class="n">v</span><span class="o">--</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">O</span><span class="p">(</span><span class="n">N</span><span class="p">);</span> <span class="n">iota</span><span class="p">(</span><span class="n">O</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">O</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="mi">1</span><span class="p">);</span> <span class="k">do</span><span class="p">{</span> <span class="kt">bool</span> <span class="n">flag</span> <span class="o">=</span> <span class="nb">true</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">u</span><span class="p">,</span><span class="n">v</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">O</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">O</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">K</span><span class="p">){</span> <span class="n">flag</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span> <span class="p">}</span> <span class="n">R</span> <span class="o">+=</span> <span class="n">flag</span><span class="p">;</span> <span class="p">}</span><span class="k">while</span><span class="p">(</span><span class="n">next_permutation</span><span class="p">(</span><span class="n">O</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">O</span><span class="p">.</span><span class="n">end</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> </code></pre></div></div>JusticeHui총평 1, 2, 3, 4번 모두 작년/재작년보다 훨씬 어려워졌습니다. 많은 구현을 요구하는 1번을 풀고 나면 전형적인 문제일지 애드혹일지 감이 잡히지 않아 오만 가지 생각이 다 드는 2번과 3번 문제가 머리를 때리고, 뒤쪽 문제를 읽어보겠다고 4~5번으로 넘어가면 만점자가 한 자리 수인 문제들이 반겨줍니다. 4번과 5번은 만점자가 한 자리 수이고 풀 태스크를 제외한 모든 서브태스크를 긁는 건 쉽기 때문에 별로 문제가 안 되었지만, 3번이 정말… 힘들었습니다. 1차가 쉬웠던 이유가 2차에 어려운 문제를 몰아넣어서 그런 건가? 올해는 오랜만에 3번을 안 풀고도 본선에 진출하는 사람이 나올 것 같기도 합니다.0804-0815 PS2023-08-15T00:00:00+00:002023-08-15T00:00:00+00:00https://justicehui.github.io/ps/2023/08/15/0804-0815<h3 id="문제-목록">문제 목록</h3> <p>12일 동안 푼 60문제 중 12문제를 골라서 풀이를 작성합니다.</p> <ul id="problem-list"></ul> <script type="text/javascript" src="https://code.jquery.com/jquery-3.1.1.min.js"></script> <script type="text/javascript"> const problem_list = '16243,16242,24276,11776,16904,13946,8177,4223,17512,20608,4815,12456'.split(','); function showProblems(){ let inner = ''; for(const i of problem_list){ inner += `<li><span id='tier-${i}'></span> <a id='title-${i}' target='_blank' href='#'></a></li>\n`; } document.getElementById('problem-list').innerHTML = inner; let query_string = ''; for(let i=0; i<problem_list.length; i++){ query_string += `id:${problem_list[i]}`; if(i + 1 < problem_list.length) query_string += '|'; } $.ajax({ type: 'GET', url: 'https://proxy.jeoungh-nah.workers.dev/https://solved.ac/api/v3/search/problem?query=' + query_string, dataType: 'json', timeout: 10000, cache: false, success: function(json) { const arr = json.items; for(let i=0; i<arr.length; i++){ const id = arr[i].problemId; const tier = arr[i].level; const title = arr[i].titleKo; const img_tag = document.getElementById(`tier-${id}`); const a_tag = document.getElementById(`title-${id}`); const url = `https://static.solved.ac/tier_small/${tier}.svg`; img_tag.style.cssText = `width: 12px; height: 15px; background-image: url(${url}); display:inline-block`; a_tag.href = `http://icpc.me/${id}`; a_tag.innerText = `BOJ ${id} ${title}`; } } }); } showProblems(); </script> <h3 id="boj-16243-teoreticar">BOJ 16243 Teoreticar</h3> <p><a href="https://www.acmicpc.net/problem/16243">문제 링크</a></p> <blockquote> <p>이분 그래프 $G=(L\cup R,E)$가 주어진다. 최소 간선 채색 수를 $OPT$라고 할 때, $2^{\lceil \log_2 OPT\rceil}$개 이하의 색을 이용해 간선을 색칠하는 문제<br />$L,R \leq 100\,000;$ $M\leq500\,000$</p> </blockquote> <p>그래프의 간선 채색 수는 차수의 최댓값보다 작을 수 없고, 이분 그래프에서는 홀의 결혼 정리를 이용하면 항상 차수의 최댓값 만큼의 색으로 간선을 칠할 수 있음을 보일 수 있습니다. 즉, $OPT = \max \text{deg}(v)$입니다.</p> <p>문제 제한에서 $\log_2 OPT$ 같은 게 보이니 분할 정복을 생각해 봅시다. 구체적으로, 모든 간선의 색을 구하기 위해 깊이가 최대 $\lceil \log_2 OPT \rceil$인 분할 정복을 하면서, 매번 간선 집합을 크기가 절반 두 개의 집합으로 분할한 다음 두 집합을 서로 다른 색으로 칠할 것입니다. 깊이가 $d$인 분할 정복 과정에서 한쪽 집합은 $2^d$를 나타내는 비트를 끄고 다른 집합은 $2^d$를 나타내는 비트를 켜는 것이라고 생각해도 됩니다.</p> <p>같은 정점을 공유하는 간선이 없도록 간선 집합을 분할해야 하는데, 이건 그래프의 오일러 투어를 구한 다음 홀수 번째 간선과 짝수 번째 간선으로 나누면 쉽게 처리할 수 있습니다. 오일러 투어는 간선 개수에 비례하는 시간에 구할 수 있으므로 시간 복잡도는 $T(M)=2T(M/2)+O(M)=O(M \log M)$이 됩니다.</p> <h3 id="boj-16242-strah">BOJ 16242 Strah</h3> <p><a href="https://www.acmicpc.net/problem/16242">문제 링크</a></p> <blockquote> <p><code class="language-plaintext highlighter-rouge">.</code>과 <code class="language-plaintext highlighter-rouge">#</code>으로 구성된 $N\times M$ 크기의 격자가 주어진다. 격자의 각 칸마다, 그 점을 포함하면서 <code class="language-plaintext highlighter-rouge">.</code>으로만 구성된 직사각형의 개수를 모두 더한 값을 구하는 문제<br />$N,M \leq 2\,000$</p> </blockquote> <p>각 점을 포함하는 직사각형의 개수를 세는 것은 결국 만들 수 있는 모든 직사각형의 넓이를 더하는 것과 같습니다. 직사각형의 넓이로 보는 편이 히스토그램과 같은 전형적인 테크닉을 적용하기 편하므로 넓이의 합을 구하는 문제라고 생각합시다. 이 문제는 스택을 사용해서 해결할 수도 있지만, 정리해야 할 게 많은 것 같아서 시간 복잡도에 $\log M$이 붙는 대신 식 정리가 조금 더 간단해 보이는 분할 정복을 사용했습니다.</p> <p>문제를 본격적으로 풀기에 앞서, $A(i,j)$에서 출발해 <code class="language-plaintext highlighter-rouge">#</code>을 만나지 않고 올라갈 수 있는 최대 길이를 $H(i, j)$라고 정의합시다. 간단한 점화식을 이용해 $O(NM)$ 시간에 모두 계산할 수 있습니다.</p> <p>이제 직사각형의 밑변이 될 행을 고정한 다음, 각 행에 대해 $O(M \log M)$에 해결할 것입니다. $m$번째 막대를 조금이라도 포함하는 모든 직사각형의 넓이를 구하는 방식으로 진행합니다. $l$번째 막대부터 $r$번째 막대만 고려했을 때, $m = \lfloor (l+r)/2 \rfloor$번째 막대를 지나는 모든 직사각형의 넓이를 $O(r-l)$ 시간에 구할 수 있다면 각 행을 $O(M \log M)$에 처리할 수 있습니다.</p> <p>직사각형의 왼쪽 변의 위치 $s$와 오른쪽 변의 위치 $e$ ($l \leq s \leq m \leq e \leq r$)를 선택해서 만들 수 있는 직사각형의 최대 높이 $f(s,e)$를 생각해 봅시다. $f(s, e) = \min\left{H(i,s),H(i,s+1),\cdots,H(e)\right}$이므로 $[l,r]$ 구간에서 나올 수 있는 서로 다른 $f(s,e)$의 값은 최대 $O(r-l)$가지입니다. 그 높이를 각각 $h_1&lt;h_2&lt;\cdots$ 이라고 하고, $f(s,e) = h_k$를 만족하는 가장 큰 구간을 $[s_i,e_i]$라고 합시다. $s_i \leq s_{i+1} \leq e_{i+1} \leq e_i$를 만족한다는 것은 쉽게 알 수 있습니다. $s_i$와 $e_i$는 투 포인터를 이용해 $O(r-l)$ 시간에 구할 수 있습니다.</p> <p>이제, 높이가 작은 것부터 차례대로 처리합시다. 즉, $m$번째 막대를 지나면서 높이가 $(h_{i-1}, h_i]$인 직사각형의 넓이의 합을 구할 것이고, 다음과 같은 식을 계산하면 됩니다.</p> \[\displaystyle \sum_{h=h_{i-1}}^{h_i}\sum_{x=s_i}^{m}\sum_{y=m}^{e_i} h(y-x+1)\] <p>이 식은 열심히 전개하면 $S(h_{i-1},h_i) \times \left{ L(s_i,m)S(m,e_i) + L(m,e_i)S(s_i,m) + L(s_i,m)L(m,e_i) \right}$가 되고, 이는 상수 시간에 계산할 수 있습니다. (단, $L(a,b)=b-a+1,S(a,b)=(a+b)(b-a+1)/2$)<br />따라서 $m$을 지나는 모든 직사각형의 넓이의 합을 $O(r-l)$ 시간에 해결할 수 있고, 각 행을 $O(M \log M)$ 시간에 처리할 수 있으므로 전체 문제를 $O(NM \log M)$ 시간에 해결할 수 있습니다.</p> <h3 id="boj-24276-circle">BOJ 24276 Circle</h3> <p><a href="https://www.acmicpc.net/problem/24276">문제 링크</a></p> <blockquote> <p>원의 둘레를 따라 $N$개의 정점이 있고, 정점들은 시계 방향으로 $1$부터 $N$까지의 번호가 매겨져 있다. $M$개의 간선이 주어지는데, 간선은 정점을 제외한 곳에서 교차하지 않는다. 최소 개수의 색으로 그래프의 정점을 칠하는 문제<br />$2 \leq N \leq 5\times 10^5;$ $1 \leq M \leq 5\times 10^5$</p> </blockquote> <p>색깔은 얼마나 많이 필요할까요? 일단 간선이 서로 교차하지 않는 평면 그래프이므로 4개 이하의 색으로 칠할 수 있음은 쉽게 알 수 있습니다. 조금 더 생각해 보면, 문제의 조건을 충족한 채로 간선을 더이상 추가하지 못하는 상황인 그래프는 볼록 다각형의 삼각분할 형태일 것이고, 바깥에 있는 삼각형부터 하나씩 떼어낸다고 생각하면 3개의 색으로 칠할 수 있다는 것을 알 수 있습니다.</p> <p>실제로 3개의 색으로 칠하는 방법도 이러한 관점에서 생각하는 것이 편합니다. 삼각형을 하나씩 떼어낸다는 것은 차수가 2인 점을 녹여서 두 간선을 병합하는 것이라고 생각할 수 있습니다. 따라서 위상 정렬과 비슷하게 degree가 2인 정점을 하나씩 제거한 다음, 제거된 순서의 역순으로 색칠할 수 있는 가장 작은 번호의 색으로 색칠하면 됩니다.</p> <p>2개의 색으로 칠할 수 있는 이분 그래프만 예외처리하면 어렵지 않게 문제를 해결할 수 있습니다.</p> <p>사실 문제에서 주어지는 그래프는 outer planar graph이므로 treewidth가 2 이하이기 때문에 항상 3개 이하의 색으로 칠할 수 있음을 바로 보일 수도 있습니다. 삼각형을 떼어내는 것은 chordal graph의 perfect elimination ordering을 구하는 것, degree가 2인 정점을 녹이는 것은 treewidth가 2인 그래프의 tree decomposition을 구하는 것과 비슷한 느낌이라서 그래프 관련해서 다양한 개념을 공부했다면 자연스럽게 떠올릴 수 있는데… 푼 사람이 많은 걸 보면 몰라도 전혀 상관 없는 것 같습니다.</p> <h3 id="boj-11776-nekameleoni">BOJ 11776 NEKAMELEONI</h3> <p><a href="https://www.acmicpc.net/problem/11776">문제 링크</a></p> <blockquote> <p>$1\ldots K$ 범위의 원소로 구성된 배열 $A[1\ldots N]$이 주어진다. 배열의 값을 변경하는 쿼리가 주어질 때마다 $1\ldots K$를 모두 포함하는 가장 작은 구간의 크기를 구하는 문제<br />$N,Q\leq 100\,000;$ $K \leq 50$</p> </blockquote> <p>$K$가 50 이하로 매우 작다는 것에 주목합시다. 구간 합의 최댓값을 관리하는 세그먼트 트리처럼 구간에 대한 정보를 적당히 저장해서 문제를 해결할 수 있습니다.</p> <p>세그먼트 트리의 각 정점에서는 (1) 정점이 담당하는 구간에서의 최소 길이, (2) 구간의 앞에서부터 원소를 누적했을 때 집합의 크기가 증가하는 위치와 그 집합, (3) 뒤에서부터 누적했을 때 집합의 크기가 증가하는 위치와 그 집합, 이렇게 세 가지 정보를 저장합니다. 원소의 종류는 $K$가지밖에 없으므로 2와 3의 크기는 공집합을 포함해서 최대 $K+1$입니다.</p> <p>두 정점의 값을 합치는 것은 대충 구현하면 $O(K^2)$에 구현할 수 있고, 투 포인터를 이용하면 $O(K)$에 구현할 수 있습니다. 따라서 전체 문제를 $O(NK+KQ\log N)$에 해결할 수 있습니다.</p> <h3 id="boj-16904-집합과-쿼리">BOJ 16904 집합과 쿼리</h3> <p><a href="https://www.acmicpc.net/problem/16904">문제 링크</a></p> <blockquote> <p>집합에 양의 정수를 추가하는 쿼리와 제거하는 쿼리가 주어진다. 쿼리를 수행할 때마다 모든 원소를 XOR한 값이 최대인 부분 집합을 찾는 문제<br />$N \leq 500\,000;$ $1 \leq x \leq 2\times 10^9;$ 오프라인 가능</p> </blockquote> <p>오프라인 동적 연결성과 같은 방식으로 분할 정복을 이용해 해결할 수 있습니다. basis의 크기는 30 이하이므로 굳이 롤백 연산을 구현할 필요 없이, 단순히 재귀 호출할 때 basis 배열을 call by value 방식으로 넘겨도 충분합니다. 따라서 원소가 삭제되는 상황에서 xor basis를 관리할 필요는 없고, 원소가 추가되는 상황만 고려해도 문제를 해결할 수 있습니다.</p> <p>코드: <a href="http://boj.kr/5f07eaa12e89438e9d2fdfd45d62da58">http://boj.kr/5f07eaa12e89438e9d2fdfd45d62da58</a></p> <h3 id="boj-13946-bipartite-blanket">BOJ 13946 Bipartite Blanket</h3> <p><a href="https://www.acmicpc.net/problem/13946">문제 링크</a></p> <blockquote> <p>정점에 가중치가 있는 이분 그래프 $G=(L\cup R,E)$가 주어진다. 가중치의 합이 $T$ 이상이면서 완전 매칭이 존재하는 정점 집합 $V\subseteq L\cup R$의 개수를 구하는 문제<br />$L,R\leq 20;$ $T \leq 4\times 10^8$</p> </blockquote> <p>두 정점 집합 $A\subset L,B\subset R$가 주어졌을 때, $A$의 모든 정점을 포함하는 매칭이 존재할 필요 충분 조건은 모든 $a\subset A$에 대해 $\vert a\vert \leq \vert N(a)\vert$입니다(홀의 결혼 정리). 이 정리를 이용하면, 완전 매칭이 존재할 정점 집합 $V$는 홀의 정리에서 제시한 조건을 만족하는 $A\subset L$과 $B\subset R$의 합집합입니다. 조건을 만족하는 $A, B$는 $O(n2^n+m2^m)$ 시간에 구할 수 있습니다. 가중치의 합이 $T$ 이상인 쌍은 정렬한 다음 투 포인터를 이용해 쉽게 찾을 수 있습니다.</p> <h3 id="boj-8177-ice-skates">BOJ 8177 Ice Skates</h3> <p><a href="https://www.acmicpc.net/problem/8177">문제 링크</a></p> <blockquote> <p>발 사이즈가 $r$인 사람은 크기가 $r$ 이상 $r+D$ 이하인 스케이트화를 신을 수 있다. 크기가 $1, 2, \cdots, N$인 스케이트화가 각각 $K$개씩 있을 때, 사람이 추가/제거되는 쿼리가 $Q$번 주어질 때마다모든 사람이 스케이트화를 신을 수 있는지 판별하는 문제<br />$D &lt; N \leq 200\,000;$ $M \leq 500\,000;$ $K\leq 10^9$</p> </blockquote> <p>홀의 정리를 사용하면 될 것처럼 생겼습니다. 발 사이즈가 $i$인 사람의 수를 $C_i$라고 하면, 모든 $1 \leq l \leq r \leq N-D$에 대해 $A_l+A_{l+1}+\cdots A+r \leq K(r-l+1+D)$를 만족하는지 확인하면 됩니다. 식을 변형하면 $\sum_{i=l}^r A_i-K \leq KD$가 되고, 이는 $A_i-K$의 부분 합의 최댓값이 $K\times D$보다 작은지 확인하는 것과 같습니다. 따라서 부분 합의 최댓값을 관리하는 세그먼트 트리, 흔히 금광 세그라고 부르는 자료구조를 이용하면 $O(N+Q\log N)$ 시간에 문제를 해결할 수 있습니다.</p> <h3 id="boj-4223-mummy-madness">BOJ 4223 Mummy Madness</h3> <p><a href="https://www.acmicpc.net/problem/4223">문제 링크</a></p> <blockquote> <p>당신과 $N$명의 미라들은 격자 위에서 턴을 주고 받으며 술래잡기를 한다. 당신이 먼저 턴을 갖는데, 인접한 8개의 칸 중 하나로 이동하거나 가만히 있을 수 있다. 그 다음에 $N$명의 미라가 모두 이동하는데, 미라는 단순히 당신과 유클리드 거리가 최소가 되는 인접한 사각형으로 이동한다. 최선을 다해 미라를 피해다닌다고 할 때, 몇 턴이 지난 후에 미라에게 잡히게 되는지 구하는 문제<br />$N \leq 10^5;$ $-10^6 \leq x_i,y_i \leq 10^6$</p> </blockquote> <p>각 개체가 $k$턴 동안 이동할 수 있는 범위는 한 변의 길이가 $2k+1$인 정사각형이라고 생각할 수 있습니다. 로봇은 항상 가까워지는 방향으로 움직이기 때문에 최선을 다한다고 생각할 수 있고, 따라서 플레이어가 미라의 이동 가능 범위로 들어가면 무조건 $k$턴 안에 잡히게 됩니다.</p> <p>따라서 $k$턴 안에 잡히는지 확인하는 결정 문제를 해결하는 파라메트릭 서치를 생각할 수 있습니다. 결정 문제의 파라미터로 $k$가 주어지면, 각 미라를 중심으로 하는 한 변의 길이가 $2k+1$인 정사각형들의 합집합이 플레이어를 중심으로 하는 정사각형을 모두 커버하는지 확인하면 됩니다. 이러한 결정 문제는 미라의 이동 범위와 플레이어의 이동 범위의 교집합인 직사각형의 합집합의 넓이가 $(2k+1)^2$인지 확인하는 것으로 해결할 수 있고, 직사각형 합집합의 넓이를 구하는 것은 $O(N \log N)$에 할 수 있음이 잘 알려져 있습니다.</p> <p>결정 문제를 $O(N \log N)$ 시간에 해결할 수 있으므로 전체 문제를 $O(N \log N \log X)$에 해결할 수 있습니다.</p> <h3 id="boj-17512-gosu-2">BOJ 17512 Gosu 2</h3> <p><a href="https://www.acmicpc.net/problem/17512">문제 링크</a></p> <blockquote> <p>서로 다른 두 정점 사이에 정확히 한 개의 간선이 존재하는 방향 그래프(토너먼트 그래프)가 주어진다. 모든 $i &lt; j$에 대해, $S_i$에서 $S_j$로 가는 간선이 있는 정점들의 나열 $S_1, S_2, \cdots, S_{1 + \lfloor \log_2 N \rfloor}$를 구하는 문제<br />$N \leq 512$</p> </blockquote> <p>편의상 $K = 1 + \lfloor \log_2 N \rfloor$라고 합시다. $S_1$은 체인에 속한 모든 정점 $S_2, S_3, \cdots, S_K$로 가는 간선이 있어야 합니다. 마찬가지로 $S_2$는 $S_1$을 제외한 모든 정점 $S_3,\cdots, S_K$로 가는 간선이 있어야 하고, $S_3$은 $S_1,S_2$를 제외한 모든 정점으로 가는 간선이 있어야 합니다. 앞에 있는 정점부터 차례대로 하나씩 구해 봅시다.</p> <p>out-degree가 가장 큰 정점을 생각해 보면, 이 정점의 out-degree는 항상 $(N-1)/2$ 이상이라는 것을 알 수 있습니다. 그러한 정점을 $S_1$으로 둔 다음, $S_1$에서 바로 갈 수 없는 정점을 제거합시다. 그래프에는 $N/2$ 이상의 정점이 남아있는 상태입니다.</p> <p>이제 다시 out-degree가 가장 큰 정점 $S_2$를 선택합시다. 이 정점의 out-degree는 $N/4$ 이상이고, $S_1$에서 갈 수 없는 정점을 모두 제거했기 때문에 $S_2$에서 한 번에 갈 수 있는 정점은 $S_1$에서도 한 번에 갈 수 있습니다. 따라서 그 정점을 $S_2$로 둘 수 있습니다.</p> <p>이런 식으로 체인의 앞에서부터 정점을 하나씩 확정짓고 필요없는 정점을 제거하더라도, 절반 이상의 정점은 살아남기 때문에 $1+\lfloor \log_2 N\rfloor$개의 정점을 찾을 수 있습니다.</p> <h3 id="boj-20608-dynamic-convex-hull">BOJ 20608 Dynamic Convex Hull</h3> <p><a href="https://www.acmicpc.net/problem/20608">문제 링크</a></p> <blockquote> <p>사차 함수 $f_i(x)=(x-a_i)^4+b$를 추가하는 쿼리, 함수 $f_i$를 삭제하는 쿼리, $x$가 주어지면 $\max f_i(x)$를 구하는 쿼리까지, 총 3가지 쿼리를 오프라인으로 처리하는 문제<br />$Q \leq 2\times 10^5;$ $1 \leq a,x \leq 5\times 10^4;$ $1 \leq b \leq 10^{18}$</p> </blockquote> <p>주어지는 모든 함수는 $y=x^4$를 평행이동시킨 것이므로 서로 다른 두 함수 간의 교점은 최대 1개만 존재합니다. 따라서 리차오 트리에서 가장 마지막에 삽입된 함수를 제거하는 기능을 구현한 다음, 오프라인 동적 연결성 문제처럼 분할정복을 하면 $O(Q \log Q \log X)$ 정도에 문제를 해결할 수 있습니다.</p> <h3 id="boj-4815-wealthy-family">BOJ 4815 Wealthy Family</h3> <p><a href="https://www.acmicpc.net/problem/4815">문제 링크</a></p> <blockquote> <p>정점에 가중치가 있는 rooted tree가 주어진다. 조상-자손 관계인 정점들이 선택되지 않도록 정확히 $K$개의 정점을 선택할 때, 가능한 가중치 합의 최댓값을 구하는 문제<br />$N \leq 150\,000;$ $K \leq 300;$ $A_i \leq 1\,000$</p> </blockquote> <p>간단한 트리 DP 문제입니다. $D(v, k) := $ $v$를 루트로 하는 서브 트리에서 정점을 $k$개 선택했을 때의 가중치 최댓값이라고 정의하면, 크기가 $S_a,S_b$인 두 트리의 DP 값을 합치는데 $O(\min\left{S_a,K\right} \times \min\left{S_b,K\right})$ 만큼의 시간이 걸려서 전체 시간 복잡도는 $O(NK^2)$이 되어서 시간 초과를 받을 것 같지만… 사실은 $O(NK)$라서 문제를 풀 수 있습니다. KOI 19 고등부 3번 검은 돌 문제와 비슷한 원리로 시간 복잡도가 보장됩니다.</p> <h3 id="boj-12456-모닝커피-large">BOJ 12456 모닝커피 (Large)</h3> <p><a href="https://www.acmicpc.net/problem/12456">문제 링크</a></p> <blockquote> <p>수행하는데 1초가 걸리는 작업이 $N$가지 있다. $i$번째 작업은 최대 $c_i$번 할 수 있으며 한 번 수행할 때마다 $s_i$ 만큼의 돈을 얻을 수 있고, $t_i$초 이후에는 수행할 수 없다. $K$초 동안 작업을 수행하려고 할 때, 얻을 수 있는 최대 이득을 구하는 문제<br />$N \leq 100;$ $1 \leq c_i,t_i \leq K \leq 10^{12};$ $1 \leq s_i \leq 1000$</p> </blockquote> <p>마감 시간이 있는 단위 시간 작업 스케줄링 문제는 매트로이드 구조이므로 가중치가 큰 작업부터 최대한 많이 수행하는 방식의 그리디를 이용해 문제를 해결할 수 있습니다. 같은 작업이 최대 $10^{12}$개 존재하므로 각 작업을 수행할 구간을 관리해야 하며, 작업의 종류는 최대 100가지로 많지 않기 때문에 효율적으로 구현할 필요는 없습니다.</p>JusticeHui문제 목록 12일 동안 푼 60문제 중 12문제를 골라서 풀이를 작성합니다.2023 SCPC 1차예선 풀이2023-07-29T00:00:00+00:002023-07-29T00:00:00+00:00https://justicehui.github.io/review/2023/07/29/scpc-qual-1<h3 id="총평">총평</h3> <p>문제를 푸는 데 필요한 사전지식이 모두 있다는 가정하에 체감 난이도는 1 &lt; 2 &lt; 5 &lt; 4 &lt; 3 이었습니다. solvedac 기준으로는 1번 브론즈, 2번 골드 하위권, 3번 P5, 4번 P2~P3, 5번 P1 정도라고 생각합니다.</p> <p>5문제 다 푸는 것보다 문제 요약이랑 풀이 작성하는 게 더 오래 걸리네요…</p> <h3 id="증강현실-배달-안경">증강현실 배달 안경</h3> <blockquote> <p>사과 $A$개를 담을 수 있는 박스와 $B$개를 담을 수 있는 박스가 있다. 두 가지 종류의 박스를 적절히 이용해서 모든 박스가 가득차도록 $N$개의 사과를 담을 때, 사용할 수 있는 박스 개수의 최댓값을 구하는 문제. $T\leq50;$ $N \leq 10^6;$ $1\leq A,B \leq N;$ $\sum N \leq 6.7\times 10^6;$ $N$개의 사과를 모두 박스에 담을 수 있는 경우만 입력으로 주어진다.</p> </blockquote> <p>$N$이 많이 크지 않기 때문에 단순히 $A$개를 담을 수 있는 박스를 $0, 1, 2, \cdots, \lfloor N/A \rfloor$개 사용하는 경우를 모두 확인하는 것으로 문제를 해결할 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><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">A</span><span class="p">,</span> <span class="n">B</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="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span> <span class="o">&gt;&gt;</span> <span class="n">A</span> <span class="o">&gt;&gt;</span> <span class="n">B</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="o">/</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">N</span> <span class="o">-</span> <span class="n">A</span> <span class="o">*</span> <span class="n">i</span><span class="p">)</span> <span class="o">%</span> <span class="n">B</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">max</span><span class="p">(</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">N</span> <span class="o">-</span> <span class="n">A</span> <span class="o">*</span> <span class="n">i</span><span class="p">)</span> <span class="o">/</span> <span class="n">B</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> </code></pre></div></div> <h3 id="딸기-수확-로봇">딸기 수확 로봇</h3> <blockquote> <p>수직선 위에 $N$개의 딸기가 있다. 로봇은 원점에서 출발해 최대 $D$만큼 움직이면서 만나게 되는 딸기를 모두 수확할 수 있다. 로봇이 수확할 수 있는 딸기의 최대 개수를 구하는 문제. $T \leq 50;$ $N\leq 10^6;$ $D \leq 10^9;$ $\vert X_i\vert \leq 10^9;$ $\sum N \leq 1.1\times 10^6$</p> </blockquote> <p>로봇이 이동 방향을 2번 이상 전환하면 이동 거리에서 손해를 보기 때문에 방향은 최대 1번만 전환하는 경로만 고려해도 괜찮습니다. 일반성을 잃지 않고, 음의 방향으로 먼저 이동한 다음에 양의 방향으로 이동하는 경로만 생각합시다.</p> <p>좌표가 음수인 딸기들의 위치를 $0 &gt; A_1 \geq A_2 \geq \cdots\geq A_l$이라고 합시다. 이때, 음의 방향으로 $\vert A_i\vert$ 만큼 이동한 다음 양의 방향으로 $D-\vert A_i\vert$ 만큼 이동하는 경로만 고려해도 충분하다는 것은 쉽게 알 수 있습니다. 따라서 음의 방향으로 $\vert A_i\vert$ 이동하는 경로에서 수확하게 되는 딸기의 개수를 구하는 것은 위치가 $1 \leq X_j \leq D-\vert A_i\vert$를 만족하는 딸기의 개수, 위치가 $X_j = 0$을 만족하는 딸기의 개수, 그리고 $i$를 모두 더한 값과 같습니다.</p> <p>$1 \leq X_j \leq D-\vert A_i\vert$를 만족하는 딸기의 개수는 이분 탐색을 이용해 $O(\log N)$ 시간에 구할 수 있으므로 전체 문제를 $O(N \log N)$ 시간에 해결할 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">K</span><span class="p">,</span> <span class="n">R</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">Sign</span><span class="p">(</span><span class="kt">int</span> <span class="n">v</span><span class="p">){</span> <span class="k">return</span> <span class="p">(</span><span class="n">v</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="o">-</span> <span class="p">(</span><span class="n">v</span> <span class="o">&lt;</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">1</span><span class="p">,</span><span class="n">t</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">t</span><span class="p">,</span> <span class="n">V</span><span class="p">[</span><span class="n">Sign</span><span class="p">(</span><span class="n">t</span><span class="p">)</span><span class="o">+</span><span class="mi">1</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">abs</span><span class="p">(</span><span class="n">t</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">V</span><span class="p">[</span><span class="mi">2</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="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">sort</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">begin</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">end</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="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">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="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="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="mi">0</span><span class="p">][</span><span class="n">i</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">K</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span> <span class="kt">int</span> <span class="n">now</span> <span class="o">=</span> <span class="n">i</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">if</span><span class="p">(</span><span class="n">K</span> <span class="o">-</span> <span class="mi">2</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">i</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="n">now</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">K</span> <span class="o">-</span> <span class="mi">2</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">i</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">begin</span><span class="p">()</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">max</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="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">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">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">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="p">}</span> </code></pre></div></div> <h3 id="장난감">장난감</h3> <blockquote> <p>$N$개의 칸으로 구성된 원형 배열이 있고, 초기에 $i$번째 칸에 $A_i$개의 구슬이 있다. 매초 $i$번째 칸에 쇠구슬이 1개 이상 있으면 그중 1개를 $i+1$번째 칸($i=N$이면 1번 칸)으로 보낸다. 장난감의 상태는 $N-$tuple $(A_1, A_2,\cdots, A_N)$으로 정의될 때, 무한히 많이 등장하는 튜플의 개수를 구하는 문제. $T\leq 509;$ $N \leq 5\times 10^5;$ $0\leq A_i \leq 10^9;$ $\sum N \leq 3.5\times 10^6$</p> </blockquote> <p>무한이 많이 등장하는 튜플의 개수를 구하는 것은 결국 충분히 많은 시간이 흐른 뒤 등장하는 사이클의 크기를 구하는 것과 같습니다. 문제 풀이의 과정은 사이클에 포함되는 튜플의 조건(이하 종료 상태)을 찾는 것과 입력으로 주어진 튜플이 어떤 종료 상태로 바뀌는지 구하는 것, 종료 상태의 사이클 주기를 구하는 것까지 총 세 개의 단계로 나눠서 생각하는 것이 편합니다.</p> <p>종료 상태의 조건을 바로 찾는 것은 어렵기 때문에 자명한 경우부터 하나씩 생각해 봅시다. 먼저, 모든 칸에 구슬이 1개 이상 있다면 더 이상 상태가 변하지 않는다는 것은 쉽게 알 수 있습니다. 또한, 구슬이 1개 초과로 들어있는 칸이 있으면서 빈칸이 있는 경우에는 언젠가는 그 빈칸이 메꿔지게 되므로 1 초과인 칸과 0인 칸이 동시에 있을 때는 종료 상태가 될 수 없습니다. 빈칸이 있지만 구슬이 있는 칸에는 모두 1개의 구슬이 있다면 $N$초마다 같은 상태가 되므로 이때는 종료 상태가 맞습니다. 즉, 종료 상태의 조건은 다음과 같습니다:</p> <ul> <li>빈칸이 없는 경우</li> <li>각 칸에 있는 구슬의 개수가 1개 이하인 경우</li> </ul> <p>빈칸이 없는 경우에는 1초가 지나도 상태가 바뀌지 않기 때문에 사이클의 크기는 1이고, 빈칸이 있는 경우에는 사이클의 크기가 1보다 클 수 있습니다. 즉, 구슬의 전체 개수가 $N$ 이상일 때는 항상 정답이 1이므로 구슬이 $N$개 미만으로 주어질 때만 신경 써도 충분합니다. 구슬이 $N$개 미만일 때 어떤 종료 상태로 바뀌는지 구하는 방법을 생각해 봅시다.</p> <p>$A_1 &gt; 1$이고 다른 모든 칸이 비어있는 상황을 생각해 봅시다. 1번 칸이 $A_1$초 동안 구슬을 하나씩 뱉어내서 $1, 2, \cdots, A_1$칸에 구슬을 깔아놓은 다음, 그 이후로는 매초 한 칸씩 그 덩어리가 앞으로 이동하게 됩니다. $\sum A_i &lt; N$인 상황만 다룰 것이기 때문에 $N-1$초가 지나면 구슬을 뱉어내는 작업은 모두 끝나게 됩니다. $A_i &gt; 1$인 칸들끼리 서로 간섭을 일으킬 수도 있지만, 그런 칸이 2~3개 있는 상황을 직접 손으로 그려서 시뮬레이션해 보면 문제가 되지 않는다는 것을 알 수 있습니다.</p> <p>$N+1$초가 지난 상황을 생각해 봅시다. $A_i &gt; 0$이었던 칸은 $A_i$초 동안 $[i,i+A_i-1]$ 구간에 구슬을 깔아놓은 뒤, 이 구간을 $N-A_i+1 \equiv 1-A_i \pmod N$번 전진시킵니다. 즉, $N+1$초가 지나면 $A_i &gt; 0$이었던 칸은 $[i-A_i+1, i]$ 구간에 구슬을 깔아놓게 됩니다. 따라서 해당하는 구간에 1씩 더한 다음, 1 초과인 칸이 있으면 적당히 풀어주는 것으로 종료 상태를 구할 수 있습니다.</p> <p>0과 1로만 구성된 종료 상태의 주기는 KMP 알고리즘을 이용해 계산할 수 있습니다. 이건 <a href="https://www.acmicpc.net/problem/4354">BOJ</a>에도 있고 SWEA에도 있는 유명한 문제이므로 설명을 생략하겠습니다. $O(N)$ 시간에 문제를 해결할 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><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">505050</span><span class="p">],</span> <span class="n">B</span><span class="p">[</span><span class="mi">505050</span><span class="p">],</span> <span class="n">F</span><span class="p">[</span><span class="mi">505050</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">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="k">if</span><span class="p">(</span><span class="n">accumulate</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">A</span><span class="o">+</span><span class="n">N</span><span class="p">,</span> <span class="mi">0LL</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="n">N</span><span class="p">){</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"1</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">memset</span><span class="p">(</span><span class="n">B</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="kt">int</span><span class="p">)</span> <span class="o">*</span> <span class="n">N</span><span class="p">);</span> <span class="n">memset</span><span class="p">(</span><span class="n">F</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="kt">int</span><span class="p">)</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">p</span><span class="o">=</span><span class="n">i</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">j</span><span class="o">++</span><span class="p">){</span> <span class="n">B</span><span class="p">[</span><span class="n">p</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">p</span><span class="o">--</span><span class="p">)</span> <span class="n">p</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="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="o">+</span><span class="n">N</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="p">)</span> <span class="k">if</span><span class="p">(</span><span class="n">B</span><span class="p">[</span><span class="n">i</span><span class="o">%</span><span class="n">N</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">)</span> <span class="n">B</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">N</span><span class="p">]</span> <span class="o">+=</span> <span class="n">B</span><span class="p">[</span><span class="n">i</span><span class="o">%</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">B</span><span class="p">[</span><span class="n">i</span><span class="o">%</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="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">B</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">!=</span> <span class="n">B</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">F</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">B</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">B</span><span class="p">[</span><span class="n">j</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="o">=</span> <span class="o">++</span><span class="n">j</span><span class="p">;</span> <span class="k">else</span> <span class="n">F</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="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">N</span> <span class="o">%</span> <span class="p">(</span><span class="n">N</span> <span class="o">-</span> <span class="n">F</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="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">N</span> <span class="o">-</span> <span class="n">F</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="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="k">else</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">N</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> </code></pre></div></div> <h3 id="최적의-프로세스-수행-순서">최적의 프로세스 수행 순서</h3> <blockquote> <p>알파벳 소문자로 구성된 두 문자열 $S, P$가 주어진다. $S$을 적당히 분할할 건데, 분할된 모든 부분 문자열은 $P$의 접두사 형태(즉, $P[0:i]$ 형태)여야 한다. 이 조건을 지키는 최소 분할 횟수를 구하는 문제. $T\leq 55;$ $\vert S\vert, \vert P\vert \leq 2.5\times 10^5;$ $\sum \vert S\vert, \sum \vert P\vert \leq 3\times 10^6$</p> </blockquote> <p>$S$의 각 지점에서 시작하는 부분 문자열이 $P$의 접두사와 얼마나 매칭되는지 구하면, 그 이후는 간단한 동적 계획법으로 정답을 구할 수 있습니다. 즉, 모든 $0\leq i &lt; \vert S\vert$에 대해, $S[i:i+x]=P[0:x]$를 만족하는 $x = X[i]$를 모두 구한 다음, $D[i+j] \leq D[i] + 1 (1 \leq j \leq X[i])$ 를 이용해 정답을 계산할 수 있습니다.</p> <p>이제 주어진 문제를 $X[i]$를 효율적으로 계산하는 것과 점화식을 $O(N^2)$보다 빠르게 계산하는 두 개의 부분 문제로 나눠서 생각할 수 있습니다.</p> <p>먼저, $X[i]$는 Z 알고리즘을 이용하면 $O(N+M)$ 시간에 계산할 수 있습니다. Z 알고리즘은 문자열 $S$가 주어지면 $S$의 모든 접미사 $S[i:]$에 대해, $S$와 $S[i:]$의 최장 공통 부분 문자열의 길이를 선형 시간에 구하는 알고리즘입니다. 즉, $S[0\cdots]$와 $S[i\cdots]$가 일치하는 최대 길이를 구합니다. 이를 이용하면 $B+A$의 $Z$ 배열을 구하는 것으로 모든 $X[i]$를 $O(N+M)$ 시간에 구할 수 있습니다.</p> <p>이제 점화식을 빠르게 계산할 차례입니다. 점화식을 계산할 때 $D[i+1], D[i+2], \cdots, D[i+X[i]]$를 현재의 값과 $D[i]+1$ 중 더 작은 것으로 갱신하는 연산이 필요한데, 이는 연속된 구간에 최솟값 갱신을 수행하는 연산이므로 세그먼트 트리를 이용해 수행할 수 있습니다. 구간 최솟값 갱신 쿼리와 특정 지점의 값을 알아내는 쿼리는 레이지 프로퍼게이션 없이 반복문만을 이용해 구현할 수 있습니다. 점화식을 계산하는 시간 복잡도는 $O(N \log N)$입니다.</p> <p>따라서 전체 문제를 $O(M + N \log N)$ 시간에 해결할 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">segment_tree_range</span><span class="p">{</span> <span class="kt">int</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">tree</span><span class="p">;</span> <span class="k">constexpr</span> <span class="k">static</span> <span class="kt">int</span> <span class="n">INF</span> <span class="o">=</span> <span class="mh">0x3f3f3f3f</span><span class="p">;</span> <span class="n">segment_tree_range</span><span class="p">()</span> <span class="o">=</span> <span class="k">default</span><span class="p">;</span> <span class="n">segment_tree_range</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">){</span> <span class="n">sz</span> <span class="o">=</span> <span class="mi">16</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">n</span> <span class="o">+</span> <span class="mi">10</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">tree</span> <span class="o">=</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="o">*</span> <span class="mi">2</span><span class="p">,</span> <span class="n">INF</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">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">,</span> <span class="kt">int</span> <span class="n">v</span><span class="p">){</span> <span class="k">for</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">l</span><span class="o">&lt;=</span><span class="n">r</span><span class="p">;</span> <span class="n">l</span><span class="o">/=</span><span class="mi">2</span><span class="p">,</span> <span class="n">r</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">l</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="n">tree</span><span class="p">[</span><span class="n">l</span><span class="p">]</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">tree</span><span class="p">[</span><span class="n">l</span><span class="p">],</span> <span class="n">v</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">tree</span><span class="p">[</span><span class="n">r</span><span class="p">]</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">tree</span><span class="p">[</span><span class="n">r</span><span class="p">],</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="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">x</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> <span class="kt">int</span> <span class="n">res</span> <span class="o">=</span> <span class="n">INF</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="n">sz</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="mi">2</span><span class="p">)</span> <span class="n">res</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">tree</span><span class="p">[</span><span class="n">x</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="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">Z</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="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">z</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="n">z</span><span class="p">[</span><span class="mi">0</span><span class="p">]</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">1</span><span class="p">,</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="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">size</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">&lt;</span> <span class="n">r</span><span class="p">)</span> <span class="n">z</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">r</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">z</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="n">l</span><span class="p">]);</span> <span class="k">while</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="n">z</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">s</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="n">z</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">z</span><span class="p">[</span><span class="n">i</span><span class="p">]])</span> <span class="n">z</span><span class="p">[</span><span class="n">i</span><span class="p">]</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="n">z</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">r</span><span class="p">)</span> <span class="n">r</span> <span class="o">=</span> <span class="n">i</span><span class="o">+</span><span class="n">z</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">l</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="n">z</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">M</span><span class="p">,</span> <span class="n">X</span><span class="p">[</span><span class="mi">252525</span><span class="p">],</span> <span class="n">D</span><span class="p">[</span><span class="mi">252525</span><span class="p">];</span> <span class="n">string</span> <span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">S</span><span class="p">;</span> <span class="n">segment_tree_range</span> <span class="n">T</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">A</span> <span class="o">&gt;&gt;</span> <span class="n">B</span><span class="p">;</span> <span class="n">S</span> <span class="o">=</span> <span class="n">B</span> <span class="o">+</span> <span class="s">"#"</span> <span class="o">+</span> <span class="n">A</span><span class="p">;</span> <span class="n">N</span> <span class="o">=</span> <span class="n">A</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">B</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">V</span> <span class="o">=</span> <span class="n">Z</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">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</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">min</span><span class="p">({</span><span class="n">M</span><span class="p">,</span> <span class="n">N</span><span class="o">-</span><span class="n">i</span><span class="p">,</span> <span class="n">V</span><span class="p">[</span><span class="n">M</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">T</span> <span class="o">=</span> <span class="n">segment_tree_range</span><span class="p">(</span><span class="n">N</span><span class="p">);</span> <span class="n">T</span><span class="p">.</span><span class="n">update</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="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">D</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">T</span><span class="p">.</span><span class="n">query</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">X</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">continue</span><span class="p">;</span> <span class="kt">int</span> <span class="n">le</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">ri</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">N</span><span class="p">,</span> <span class="n">i</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">T</span><span class="p">.</span><span class="n">update</span><span class="p">(</span><span class="n">le</span><span class="p">,</span> <span class="n">ri</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="mi">1</span><span class="p">);</span> <span class="p">}</span> <span class="n">cout</span> <span class="o">&lt;&lt;</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="o">&lt;</span> <span class="mf">1e9</span> <span class="o">?</span> <span class="n">D</span><span class="p">[</span><span class="n">N</span><span class="p">]</span> <span class="o">:</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="p">}</span> </code></pre></div></div> <h3 id="타이젠">타이젠</h3> <blockquote> <p>총 $M$개의 내부 상태를 갖는 시스템에서 $N$개의 작업을 수행해야 한다. $i$번째 작업은 $[L_i,R_i]$ 시간 구간 동안 수행되어야 하고, $0=L_1&lt;R_1&lt;L_2&lt;R_2&lt;\cdots&lt;L_N &lt; R_N$이 성립하므로 모든 작업의 수행 시간은 겹치지 않는다. 시스템은 $i$번째 상태에 있을 때 시간당 $P_i$ 만큼의 전력을 소모하고, $P_1&gt;P_2&gt;\cdots&gt;P_M$이 성립한다. 작업이 수행되는 동안에는 반드시 1번 상태에 있어야 하며, 수행하지 않는 동안에는 다른 상태로 자유롭게 바꿀 수 있다. $i$번째 상태에서 $j(&gt;i)$번째 상태로 바꾸는데 $W_j - W_i$ 만큼의 전력을 소모하고, $j(&gt;i)$번째 상태에서 $i$번째 상태로 바꿀 때는 전력을 소모하지 않는다. 이때 $0=W_1\leq W_2\leq \cdots \leq W_M$이 성립한다. 시스템이 $N$개의 작업을 모두 수행하는 데 필요한 전력 소모량의 최솟값을 구하는 문제 $T\leq 45;$ $N,M \leq 10^5;$ $0=L_1&lt;R_1&lt;L_2&lt;R_2\cdots&lt;L_N&lt;R_N \leq 10^{11};$ $10^7\geq P_1&gt; P_2&gt; \cdots &gt; P_M\geq 0;$ $0=W_1\leq W_2\leq \cdots \leq W_M\leq 10^{11}$</p> </blockquote> <p>작업 구간일 때는 1번 상태에 있어야 하므로 이때 소모하는 전력량은 상수 취급해도 됩니다. 따라서 수면 구간에서의 비용만 최소화하면 되고, 각각의 수면 구간에서 상태를 여러 번 바꿔서 이득을 보는 일은 없기 때문에 한 번의 수면 구간에서는 한 개의 상태만 선택하는 경우만 고려해도 됩니다.</p> <p>길이가 $x$인 수면 구간을 $i$번째 상태에서 보낼 때 소모하는 전력의 양은 $P_ix+W_i$입니다. 비용이 일차 함수 꼴이기 때문에 Convex Hull Trick을 사용할 수 있고, 심지어 $P_i$가 순감소하므로 수면 구간을 길이 오름차순으로 정렬하면 CHT를 선형 시간에 할 수 있습니다. 수면 구간을 정렬해야 하므로 전체 시간 복잡도는 $O(N \log N)$입니다.</p> <p>$P_i$에 순감소 조건이 붙어있어서 비교적 복잡한 자료구조(li-chao tree, line container, …)가 필요하지 않고, $P_i\leq 10^7;L_i,R_i,W_i\leq 10^{11}$ 제한 덕분에 <code class="language-plaintext highlighter-rouge">long long</code>만 써서 교점을 비교할 수 있다는 점에서 출제자의 너그러운 마음을 확인할 수 있었습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">line</span><span class="p">{</span> <span class="n">ll</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">;</span> <span class="n">line</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="o">:</span> <span class="n">a</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">b</span><span class="p">)</span> <span class="p">{}</span> <span class="n">ll</span> <span class="n">f</span><span class="p">(</span><span class="n">ll</span> <span class="n">x</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">a</span> <span class="o">*</span> <span class="n">x</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</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">M</span><span class="p">,</span> <span class="n">L</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="mi">101010</span><span class="p">],</span> <span class="n">P</span><span class="p">[</span><span class="mi">101010</span><span class="p">],</span> <span class="n">W</span><span class="p">[</span><span class="mi">101010</span><span class="p">],</span> <span class="n">X</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">H</span><span class="p">;</span> <span class="kt">bool</span> <span class="nf">Check</span><span class="p">(</span><span class="n">line</span> <span class="n">a</span><span class="p">,</span> <span class="n">line</span> <span class="n">b</span><span class="p">,</span> <span class="n">line</span> <span class="n">c</span><span class="p">){</span> <span class="k">return</span> <span class="p">(</span><span class="n">a</span><span class="p">.</span><span class="n">b</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="o">*</span> <span class="p">(</span><span class="n">b</span><span class="p">.</span><span class="n">a</span> <span class="o">-</span> <span class="n">c</span><span class="p">.</span><span class="n">a</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="p">(</span><span class="n">c</span><span class="p">.</span><span class="n">b</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="o">*</span> <span class="p">(</span><span class="n">b</span><span class="p">.</span><span class="n">a</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="p">}</span> <span class="kt">void</span> <span class="nf">Insert</span><span class="p">(</span><span class="n">line</span> <span class="n">l</span><span class="p">){</span> <span class="k">while</span><span class="p">(</span><span class="n">H</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&gt;=</span> <span class="mi">2</span> <span class="o">&amp;&amp;</span> <span class="n">Check</span><span class="p">(</span><span class="n">H</span><span class="p">[</span><span class="n">H</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="n">H</span><span class="p">.</span><span class="n">back</span><span class="p">(),</span> <span class="n">l</span><span class="p">))</span> <span class="n">H</span><span class="p">.</span><span class="n">pop_back</span><span class="p">();</span> <span class="n">H</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">l</span><span class="p">);</span> <span class="p">}</span> <span class="n">ll</span> <span class="nf">Query</span><span class="p">(</span><span class="n">ll</span> <span class="n">x</span><span class="p">){</span> <span class="k">while</span><span class="p">(</span><span class="n">X</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">&lt;</span> <span class="n">H</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">H</span><span class="p">[</span><span class="n">X</span><span class="p">].</span><span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="n">H</span><span class="p">[</span><span class="n">X</span><span class="o">+</span><span class="mi">1</span><span class="p">].</span><span class="n">f</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="p">;</span> <span class="k">return</span> <span class="n">H</span><span class="p">[</span><span class="n">X</span><span class="p">].</span><span class="n">f</span><span class="p">(</span><span class="n">x</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">L</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&gt;&gt;</span> <span class="n">R</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="n">cin</span> <span class="o">&gt;&gt;</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">1</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="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">M</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">W</span><span class="p">[</span><span class="n">i</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="n">vector</span><span class="o">&lt;</span><span class="n">ll</span><span class="o">&gt;</span> <span class="n">len</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">res</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">L</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="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">2</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">len</span><span class="p">.</span><span class="n">push_back</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="o">-</span> <span class="n">R</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">sort</span><span class="p">(</span><span class="n">len</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">len</span><span class="p">.</span><span class="n">end</span><span class="p">());</span> <span class="n">H</span><span class="p">.</span><span class="n">clear</span><span class="p">();</span> <span class="n">X</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">M</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">Insert</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="n">W</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="k">auto</span> <span class="n">i</span> <span class="o">:</span> <span class="n">len</span><span class="p">)</span> <span class="n">res</span> <span class="o">+=</span> <span class="n">Query</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="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div>JusticeHui총평 문제를 푸는 데 필요한 사전지식이 모두 있다는 가정하에 체감 난이도는 1 &lt; 2 &lt; 5 &lt; 4 &lt; 3 이었습니다. solvedac 기준으로는 1번 브론즈, 2번 골드 하위권, 3번 P5, 4번 P2~P3, 5번 P1 정도라고 생각합니다.ICPC 준비의 첫걸음: 공부 방법과 대회 전략2023-05-30T00:00:00+00:002023-05-30T00:00:00+00:00https://justicehui.github.io/etc/2023/05/30/icpc-preparation<h2 id="서론">서론</h2> <p><img src="/img/20230504skku.png" style="width:50%" /><br /> 지난 5월 4일에 성균관대학교에서 강연했던 것을 정리한 글입니다. 다음과 같은 내용을 다룹니다.</p> <ol> <li>어떤 문제를 푸는 대회인가?</li> <li>어떤 것에 초점을 맞춰서 공부해야 하는가?</li> <li>최근 기출 문제에서 등장하는 알고리즘</li> <li>전공과목과 연계되는 내용</li> <li>대회 전략과 팀 워크</li> </ol> <h2 id="목차">목차</h2> <ul> <li>ICPC 대회 소개 <ul> <li>프로그래밍 대회란?</li> <li>ICPC 소개</li> </ul> </li> <li>필요한 능력과 훈련 방법 <ul> <li>배경지식</li> <li>문제 해결 능력</li> <li>구현 능력</li> </ul> </li> <li>고수가 되는 방법 <ul> <li>문제를 푸는 방법</li> <li>잘해지는 방법</li> </ul> </li> <li>최근 대회 분석 <ul> <li>2020 ~ 2022 ICPC 예선</li> <li>2018 ~ 2022 ICPC 본선</li> <li>수상을 노린다면…</li> </ul> </li> <li>학교 전공과목과의 연계</li> <li>대회 전략과 팀 워크 <ul> <li>대회 전략의 필요성</li> <li>스코어보드 활용</li> <li>디버깅</li> <li>다른 팀원이 키보드를 잡고 있을 때</li> <li>키보드를 잡은 사람이 없을 때</li> <li>팀 전략의 분류</li> <li>실제 사례</li> <li>오프라인 대회장</li> </ul> </li> </ul> <h2 id="icpc-대회-소개">ICPC 대회 소개</h2> <h4 id="프로그래밍-대회란">프로그래밍 대회란?</h4> <p>프로그래밍 경시대회는 주어진 시간 동안 주어진 문제를 최대한 많이 푸는 형식의 대회입니다. 대회마다 차이가 있지만 보통 개인 대회는 4~5시간 동안 3~4문제, 팀 대회는 3~5시간 동안 10~12문제를 풀어야 합니다. 다른 대회와 조금 다른 점은 실시간으로 모든 참가자의 점수를 알 수 있다는 것입니다. 대회 도중에 아래 사진과 같은 스코어보드가 제공되어서, 각 팀이 어떤 문제를 몇 번 시도해서 해결했는지 확인할 수 있습니다.</p> <p><img src="/img/icpc22.png" alt="" /></p> <p>대회에는 주어진 상황을 직접 시뮬레이션하는 문제, 주어진 수식을 효율적으로 계산하는 문제, 경우의 수를 세는 문제, 조건을 만족하는 최대/최솟값을 찾는 최적화 문제 등 다양한 문제가 출제됩니다. Problem Solving에 대한 전반적인 내용은 글의 주제를 벗어나므로 ho94949님께서 제작하신 <strong>Problem solving</strong> 슬라이드(<a href="https://www.slideshare.net/ho94949/problem-solving-60463388">링크</a>)를 참고하시길 바랍니다.</p> <h4 id="icpc-소개">ICPC 소개</h4> <p>ICPC는 국제 결승의 역할을 하는 World Finals와 지역 예선의 역할을 하는 Regional Contest로 구성되어 있고, 한국 대학교 팀들은 주로 Asia Seoul Regional Contest에 참가합니다. 서울 지역 대회는 한국 대학생 프로그래밍 경시대회 본선을 겸하기 때문에 대통령상, 국무총리상, 장관상 등 높은 상들이 걸려있습니다.</p> <p>대회는 3인 1팀으로 진행되며, 각 팀은 1대의 컴퓨터만 사용할 수 있습니다. 출제 범위가 정해져 있는 올림피아드(<a href="https://ioinformatics.org/page/syllabus/12">링크</a>)와 다르게 ICPC는 출제 범위가 정해져 있지 않습니다. 따라서 각 팀은 25페이지 이내의 문서(팀 노트)를 자유롭게 제작해서 지참할 수 있습니다. 3명이 1대의 컴퓨터만 사용할 수 있다는 점과 팀 노트의 존재 때문에 대회 전략이 대회 성적에 많은 영향을 미칩니다.</p> <p>서울 지역 대회에 대해 조금 더 자세하게 알아보면, 서울 지역 대회는 예선과 본선으로 구성되어 있습니다. 예선은 보통 10월에 개최되며 3시간 동안 10~12문제를 해결해야 합니다. 모든 팀은 지도 교수의 감독하에 예선을 응시해야 하고, 대부분의 학교는 모든 팀이 한 장소에 모여서 응시하는 것으로 알고 있습니다.</p> <p>각 학교마다 예선 등록 팀 수의 절반 이하만 본선에 진출 가능하기 때문에 학교마다 본선 진출 커트라인이 다릅니다. (<a href="http://icpckorea.org/archives/2472">링크</a>의 1/2 규칙 참고) 1/2 규칙을 만족하는 팀 중 n문제 이상 푼 대학 내 m등 팀을 본선에 올리는 방식으로 본선 진출 팀을 선정합니다. ICPC에서 좋은 성적을 내는 학교일수록 본선 진출이 어려운 편이며, 주로 <code class="language-plaintext highlighter-rouge">서울대학교 &gt;&gt;&gt;&gt;&gt; 카이스트 = 고려대학교 &gt;&gt;&gt; 서강대학교 = 성균관대학교 = 한양대학교 = 숭실대학교</code> 순으로 어렵습니다. 특히 서울대학교는 본선에 진출하면 수상이 거의 확정될 정도로 본선 진출 난이도가 높습니다.</p> <p>본선은 11월에 개최되며 5시간 동안 12문제를 해결해야 합니다. 예선과 다르게 본선은 모든 팀이 한 장소에 모여서 대회를 진행합니다. 대상 1팀, 금상 1팀, 은상 3팀, 동상 4팀, 장려상 5팀으로 총 14팀에게 시상하며, 매년 후원사 사정에 따라 특별상을 추가로 수여하는 것으로 보입니다. 상위 2~3개 대학의 1등 팀은 월드 파이널에 진출할 수 있습니다.</p> <h2 id="필요한-능력과-훈련-방법">필요한 능력과 훈련 방법</h2> <p>baactree님께서 작성하신 <strong>알고리즘 공부, 어떻게 해야하나요?</strong>(<a href="https://baactree.tistory.com/52">링크</a>), Barkingdog님께서 작성하신 <strong>실전 알고리즘 0x00강 오리엔테이션</strong>(<a href="https://blog.encrypted.gg/921">링크</a>)를 함께 읽어보시는 것을 추천합니다. 저도 고등학생 때 이 글을 읽으며 공부했기 때문에 비슷한 내용을 이야기합니다.</p> <p>문제를 풀 때 필요한 능력은 크게 배경지식, 문제 해결 능력, 구현 능력으로 구분해서 이야기합니다.</p> <h4 id="배경지식">배경지식</h4> <p>첫 번째는 <strong>배경지식</strong>으로, 프로그래밍 문법, 자료구조/알고리즘, 수학적 지식 등 문제를 해결하는 데 필요한 모든 지식을 의미합니다. 중학생 때 배운 이차방정식의 근의 공식을 생각해 보면, 똑똑한 사람들은 혼자서 발견하기도 하지만 대부분의 학생은 공식의 유도 과정과 그 결과를 누군가에게 배웁니다. 마찬가지로 자료구조와 알고리즘도 똑똑한 사람들은 혼자서 발견하는 경우도 있지만, 대부분의 사람은 하나씩 공부해야 합니다.</p> <p>배경지식이 부족하면 문제를 어떻게 풀지 몰라서 해설을 보는데 모르는 외계어가 적혀 있는 것을 많이 경험하게 됩니다. 반대로 이야기하면, 문제 해설에 나와 있는 모르는 키워드를 전부 공부하면 배경지식을 채울 수 있습니다.</p> <p>문제를 필요할 때 필요한 세 가지 능력 중 배경지식이 가장 훈련하기 편합니다. 책이나 강의를 보는 방법도 있고, 요즘에는 인터넷에도 정말 좋은 자료들이 많이 있어서 의지만 있다면 누구나 쉽게 공부할 수 있습니다. 가르치는 것도 가장 쉽습니다. 따라서 여러분들이 돈을 지불하면서 다른 사람에게 문제 해결을 배울 때는 배경지식 말고 문제 해결 능력이나 구현 능력을 키워달라고 요구하는 것이 좋습니다.</p> <h4 id="문제-해결-능력">문제 해결 능력</h4> <p>두 번째는 <strong>문제 해결 능력</strong>으로, 주어진 문제를 내가 알고 있는 배경지식을 사용할 수 있는 형태로 바꾸는 능력을 의미합니다. 수능 수학 30번 문제는 분명 고등학교 교육 과정에서 다루는 내용만으로 풀 수 있지만 대부분의 학생들이 해결하지 못한다는 것을 생각해 보면 문제 해결 능력이 무엇인지 쉽게 알 수 있습니다.</p> <p>문제 해결 능력이 부족하면 문제 해설을 보면서 “이걸 왜 생각 못 했지?”, “아 이거 아는 건데…“와 같은 이야기를 자주 하게 됩니다. “아 이거 아는 건데…” 라는 말을 하게 되는 상황은 대부분 제대로 몰라서 못 푼 것이기 때문에, 겸손하게 자신의 부족함을 인정하고 공부하는 것이 중요합니다.</p> <p>문제 해결 능력을 키우는 가장 좋은 방법은 좋은 머리를 갖고 태어나는 것입니다. 이건 불가능하니 다른 방법을 이야기하자면, 문제를 많이 풀고 다른 사람들이 작성한 문제 풀이를 많이 읽어보는 것이 좋습니다. 이때 풀이를 작성한 사람이 어떤 사고 과정을 거쳐서 풀이에 도달했는지 따라가는 것이 중요합니다. 풀이를 잘 작성하는 사람은 그 중간 과정을 잘 풀어서 쓰지만, 대부분의 글은 중간 과정이 생략되어 있기 때문에 그 빈 공간을 혼자 고민하면서 채워나가야 합니다.</p> <h4 id="구현-능력">구현 능력</h4> <p>마지막은 <strong>구현 능력</strong>으로, 내가 생각한 풀이 과정을 코드로 옮기는 능력을 의미합니다. 논술 대회가 아니라 프로그래밍 대회이기 때문에 결국에는 문제 해결 과정을 코드로 옮겨서 제출해야 하고, 코드로 옮기지 못하면 문제를 해결하지 못한 것과 다름없습니다.</p> <p>구현 능력이 부족하면 대회가 끝난 다음에 “풀이는 알겠는데 이걸 어떻게 구현하지?”, “아 이거 다 풀었는데…“와 같은 이야기를 자주 하게 됩니다. 다 풀었다고 생각할 수 있지만 스코어보드에는 못 푼 것으로 기록되어 있기 때문에 그냥 못 푼 것입니다.</p> <p>구현 능력을 키우는 가장 좋은 방법은 문제를 많이 풀고, 다른 사람의 코드를 많이 보면서 좋은 구현 방식을 학습하는 것입니다. 고인물을 한 명 정해서 코딩 스타일을 따라 하는 것도 좋은 방법입니다. 저는 고등학생 때 koosaga님의 코드를 많이 보면서 공부했습니다.</p> <h2 id="고수가-되는-방법">고수가 되는 방법</h2> <h4 id="문제를-푸는-방법">문제를 푸는 방법</h4> <p>사람마다 문제를 푸는 방법이 다릅니다. 크게 네 가지 정도의 유형으로 나뉘는데, 하나씩 시도해 보면서 자신에게 맞는 방법을 찾는 것이 중요합니다. 물론 모든 방법을 자유자재로 사용할 수 있으면 더 좋습니다.</p> <p>첫 번째 방법은 문제를 매우 많이 풀어서 DB에 넣어두고, 문제를 풀 때마다 DB에 쿼리를 날리는 것입니다. 똑똑하지 않은 사람들도 충분한 훈련을 통해 잘 사용할 수 있으며, 제가 주로 이 방식으로 문제를 해결합니다. 문제를 많이 풀고 복기하는 과정을 통해 다양한 유형과 풀이 방법을 기억한 다음, 비슷한 문제를 만났을 때 빠르게 꺼내서 쓸 수 있도록 연습해야 합니다.</p> <p>두 번째 방법은 관찰 - 추측 - 증명 - 관찰 - 추측 - 증명 - … 을 반복하는 것입니다. 직관력이 좋을수록 풀이까지의 경로가 짧아지는 경향이 있습니다. 직관이 별로 뛰어나지 않더라도, 다른 사람이 작성한 풀이를 읽을 때 <strong>풀이에 도달하는 사고 과정</strong>에 집중해서 읽으면 천재들의 사고 과정을 모방하는 효과를 볼 수 있습니다.</p> <p>세 번째 방법은 입력 제한과 시간제한을 보고 가능한 시간 복잡도와 알고리즘을 모두 나열하고 하나씩 대입해 보면서 생각하는 것입니다. 굉장히 이상해 보이지만 대회에서 꽤 유용합니다. 예를 들어 어떤 순서를 정하는 문제에서 $N \leq 500\,000$ 이면 그리디 문제일 확률이 높고, 시간제한이 3~5초 정도이고 $N \leq 50\,000$ 정도이면 시간 복잡도에 $\sqrt N$이 들어갈 확률이 높습니다. 물론 출제진들도 이런 것을 알고 있으므로 $O(N \log N)$에 풀 수 있는 그리디 문제에서 입력 제한을 $N \leq 400$ 정도로 주는 등의 심리전을 걸기도 합니다.</p> <p>마지막은 풀이를 찾는 Decision Tree를 만드는 것입니다. 소문으로만 들어봤는데, 익숙해지면 풀이를 굉장히 빨리 찾을 수 있다는 이야기가 있습니다.</p> <p>저는 보통 문제를 푸는 것을 미로찾기에 비유합니다. 아래 그림처럼 앞이 보이지 않는 어두운 미로에서 배경지식은 미로에 있는 촛불, 문제 해결 능력은 촛불의 밝기라고 생각해 봅시다. 배경지식을 공부하는 것은 미로에 촛불을 더 설치하는 것, 문제 해결 능력을 기르는 것은 촛불의 밝기를 키우는 것으로 생각할 수 있습니다.</p> <p><img src="https://mario.wiki.gallery/images/5/51/NSMBW_World_2-3_Screenshot.png" alt="" /></p> <blockquote> <p>Super Mario Wiki - NSMBW World 2-3 Screenshot.png</p> </blockquote> <p>위에서 말한 문제를 푸는 네 가지 방법을 미로의 관점에서 다시 생각해 볼 수 있습니다. 문제를 매우 많이 풀어서 DB에 넣는 것은 문제의 유형도 하나의 사전지식으로 취급해서 수많은 곳에 촛불을 설치하는 것이고, 관찰 - 추측 - 증명을 반복하는 것은 합리적인 근거를 토대로 인근의 광원으로 이동하는 것입니다. 가능한 시간 복잡도와 알고리즘을 나열하거나 Decision Tree를 이용하는 것은 어떤 광원에서 탐색을 시작할지 결정하는 것으로 생각할 수 있습니다.</p> <h4 id="잘해지는-방법">잘해지는 방법</h4> <p>많은 사람이 어떻게 하면 잘해질 수 있는지 물어봅니다. 문제를 많이 풀면 된다고 이야기하는 경우가 대부분이지만 사람들이 그걸 몰라서 물어보는 것은 아닐 테니까… 저는 문제를 매우 많이 풀어서 실력을 올렸기 때문에 문제를 많이 풀게 된 계기나 원동력이 무엇이었는지 고민을 했었습니다.</p> <p>제가 생각했을 때 실력이 오르는 가장 효율적인 방법은 (내가 잘하는 것 같음 → 재미있어짐 → 재미있어서 더 열심히 공부함 → 잘해짐 → 잘해서 더 재미있음 → 더 열심히 공부함 → 더 잘해짐 → …)의 사이클을 타는 것입니다. 이 사이클 안에 들어가면 크게 신경을 쓰지 않아도 실력이 꾸준히 올라갑니다. 처음부터 재미있으면 운이 좋은 거니까 감사하게 생각하면서 열심히 공부하면 되고, 그게 아니라면 일단 잘해지는 것밖에 방법이 없으니 열심히 공부하면 됩니다. 뭐 결국 열심히 해야 합니다…</p> <p>사이클 안에 들어간 다음도 중요합니다. 단기적인 성과를 뽑아내야 하는 상황이 아니라면, 스트레스를 받지 않고 PS가 재미있게 느껴지는 범위 안에서만 공부하는 것을 추천합니다. 저는 조금 극단적인 케이스인데, 재미없다고 느껴지는 순간 즉시 키보드에서 손 떼고 침대로 갑니다.</p> <h2 id="최근-대회-분석">최근 대회 분석</h2> <h4 id="2020--2022-icpc-예선">2020 ~ 2022 ICPC 예선</h4> <p>최근 3년 동안 예선에 출제된 문제의 solved.ac 난이도와 상위권 대학의 본선 진출 커트라인은 다음과 같습니다. 빠른 n문제로 표기되어 있는 대학은 문제 수가 아닌 페널티로 본선 진출이 갈린 대학교를 의미합니다.</p> <ul> <li>2020: S4 G4 G4 G2 G? P5 P4 P1 D5 D5 D? D3 <ul> <li>서울대학교: 8문제</li> <li>카이스트, 고려대학교: 6문제</li> <li>서강대학교, 성균관대학교, 한양대학교: 빠른 5문제</li> <li>숭실대학교: 5문제</li> </ul> </li> <li>2021: S5 S1 G2 G1 P4 P4 P2 P2 D5 D4 D4 D4 <ul> <li>서울대학교: 빠른 6문제</li> <li>카이스트: 5문제</li> <li>고려대학교, 성균관대학교: 빠른 4문제</li> <li>한양대학교, 숭실대학교: 4문제</li> <li>서강대학교: 빠른 3문제</li> </ul> </li> <li>2022: S4 S3 S2 G3 G2 P5 D5 D5 D4 D2 R? <ul> <li>서울대학교, 카이스트: 7문제</li> <li>고려대학교, 서강대학교: 빠른 5문제</li> <li>성균관대학교, 숭실대학교: 5문제</li> <li>한양대학교: 4문제</li> </ul> </li> </ul> <p>서울대학교와 카이스트가 아니라면 solved.ac 기준 골드 이하의 문제만 모두 해결하면 대부분 본선에 진출할 수 있습니다. ICPC 예선은 가장 쉬운 3~4문제만 한글 지문을 제공해 주기 때문에, 한글 문제를 모두 해결한 다음 스코어보드에서 가장 많이 풀린 1~2문제를 더 풀면 본선을 노려볼 수 있습니다.</p> <p>예선에서 가장 쉬운 5문제를 풀기 위해 필요한 개념은 다음과 같습니다. 기초적인 개념을 잘 활용하는 문제들이며, 본선 진출을 노린다면 어려운 배경지식을 공부하는 것보다는 알고 있는 내용을 잘 활용하는 것이 중요합니다.</p> <table> <tr> <th rowspan="2">2020</th> <td>S4</td> <td>G4</td> <td>G4</td> <td>G2</td> <td>G?</td> </tr> <tr> <td>그리디</td> <td>최단 경로</td> <td>스패닝 트리</td> <td>DP</td> <td>DFS</td> </tr> <tr> <th rowspan="2">2021</th> <td>S5</td> <td>S1</td> <td>G2</td> <td>G1</td> <td>P4</td> </tr> <tr> <td>정렬</td> <td>완전 탐색</td> <td>DP</td> <td>기하</td> <td>그리디</td> </tr> <tr> <th rowspan="2">2022</th> <td>S4</td> <td>S3</td> <td>S2</td> <td>G3</td> <td>G2</td> </tr> <tr> <td>그리디</td> <td>그리디</td> <td>그리디</td> <td>DP</td> <td>DP</td> </tr> </table> <p>서울 지역 예선과 비슷한 난이도의 대회로는 BAPC(<a href="https://www.acmicpc.net/category/89">BOJ 링크</a>), GCPC(<a href="https://www.acmicpc.net/category/47">BOJ 링크</a>), NCPC(<a href="https://www.acmicpc.net/category/46">BOJ 링크</a>), Southeast USA Regional Division 1(<a href="https://www.acmicpc.net/category/40">BOJ 링크</a>)가 있습니다. 조금 더 쉬운 대회로는 BAPC 예선, Southeast USA Regional Division 2도 있으니 팀 연습할 때 유용하게 사용하면 좋을 것 같습니다.</p> <h4 id="2018--2022-icpc-본선">2018 ~ 2022 ICPC 본선</h4> <p>본선에서 수상을 노리는 팀들은 예선보다 훨씬 더 어려운 문제를 해결해야 합니다. 최근 5년 동안 본선에 출제된 문제의 solved.ac 난이도와 수상 커트라인, 대학 3등 안에 들기 위한 커트라인은 다음과 같습니다.</p> <ul> <li>2018: B1 G2 G1 P4 P4 P4 P2 P2 P1 D5 R4 R4 <ul> <li>수상: 7문제(P2), 대학 3등: 10문제(D5)</li> </ul> </li> <li>2019: S4 G4 G3 G2 P4 D5 D5 D5 D4 D3 D2 D1 <ul> <li>수상: 7문제(D5), 대학 3등: 9문제(D4)</li> </ul> </li> <li>2020: B1 G3 G2 G2 P3 P2 P1 D5 D4 D3 D2 D1 <ul> <li>수상: 7문제(P1), 대학 3등: 8문제(D5)</li> </ul> </li> <li>2021: S4 G5 P3 P3 P3 P2 P2 D3 D3 D1 D1 R5 <ul> <li>수상: 7문제(P2), 대학 3등: 8문제(D3)</li> </ul> </li> <li>2022: S2 G4 G3 G3 P5 P3 P2 D5 D4 D3 D2 R1 <ul> <li>수상: 8문제(D5), 대학 3등: 9문제(D4)</li> </ul> </li> </ul> <p>수상을 하기 위해서는 플래티넘 이하의 모든 문제를 해결해야 하고, 월드 파이널 진출을 노리는 팀들은 다이아몬드 하위권 문제도 모두 해결할 수 있어야 합니다. 이렇게 보면 굉장히 어려워 보이지만, 다양한 꼼수가 존재합니다.</p> <h4 id="수상을-노린다면">수상을 노린다면…</h4> <p>서울 지역 대회는 플래티넘 ~ 다이아몬드 하위권 레벨에서 배경지식이 있으면 쉽게 풀 수 있는 문제가 꽤 자주 나옵니다.</p> <ul> <li>2019 예선: 컨벡스헐 트릭(D5)</li> <li>2019 본선: 센트로이드 분할(P2), 세그먼트 트리 변형(A.K.A. 금광세그, D5)</li> <li>2020 본선: 가우스 소거법(P3), FFT(P1), 분할 정복 최적화(D4), 도미네이터 트리(D2)</li> <li>2021 본선: KMP 알고리즘 변형(D3)</li> <li>2022 예선: 평방 분할(D5)</li> </ul> <p>비슷한 문제가 여러 번 출제되는 경우도 자주 보입니다.</p> <ul> <li>2019 본선 H(D5) = 2014 KOI 중등부 4번 금광</li> <li>2021 예선 L(P2) ≒ 2022 본선 C(D4)</li> <li>2021 본선 K(D3) ≒ 2011 CEOI 기출 ≒ 2020 1차 선발 기출 = 2021 SCPC 2차 예선 기출</li> <li>2022 본선 A(D5) = BOJ 16883. 대각 게임</li> <li>2022 본선 B(D2) = 2016 1차 선발 기출 ≒ 2019 2차 선발 기출 (<a href="https://kdh9949.tistory.com/45">참고 링크</a>)</li> </ul> <p>따라서 수상을 노린다면 배경지식과 흔히 웰노운 테크닉이라고 불리는 유명한 기법들을 공부하는 것이 좋습니다. 배경지식을 대회 전에 급하게 공부하는 것은 소용없고, solved.ac 티어도 올릴 겸 평소에 조금씩 공부하는 것을 추천합니다. 웰노운 테크닉은 solved.ac 클래스 문제집을 풀어도 좋고, P3..D3 범위 안에서 푼 사람이 많은 문제부터 차례대로 풀어보는 것도 좋습니다. BOJ에 올라오는 대학교 교내대회 문제도 공부할 때 유용합니다.</p> <p>팀 노트를 준비하는 것도 중요합니다. 코드는 팀 노트에 넣어 가더라도 각 알고리즘이 어떤 것을 입력받아서 무엇을 계산하는지는 알아야 합니다. 팀 노트에 넣는 코드는 빠르고 검증된 코드를 넣어야 하는데, 다른 팀들의 팀 노트를 참고하는 것도 좋고 <a href="https://judge.yosupo.jp/">Library Checker</a>라는 사이트를 이용하는 것도 좋습니다.</p> <h2 id="학교-전공과목과의-연계">학교 전공과목과의 연계</h2> <p>이산수학, 자료구조, 알고리즘을 제외한 다른 과목과는 별로 연관된 내용이 없을 것 같지만, 의외로 다른 전공과목에서 배우는 내용이 문제 해결에 도움이 되는 경우가 있습니다.</p> <p>가장 먼저 언급할 것은 <strong>컴퓨터구조</strong>입니다. 문제를 풀다 보면 흔히 상수 커팅이라고 부르는, 실행 시간을 줄여야 하는 경우가 있습니다. 가장 좋은 방법은 연산 횟수를 줄이는 것이겠지만 그게 항상 가능하지는 않습니다. 구체적으로 다음과 같은 상황이 있습니다.</p> <ul> <li>$N^2$은 시간 초과를 받지만 $N^2/8$은 AC를 받는 경우</li> <li>정해는 $O(N^2)$이지만 $O(N^3)$ 풀이만 알고 있을 때 어떻게든 문제를 풀고 싶은 경우</li> </ul> <p>둘 다 일반적인 상황은 아니지만… 아무튼 컴퓨터구조에서 배우는 캐시 히트, 분기 예측, 메모리 정렬, SIMD와 같은 내용이 큰 도움이 됩니다. (<a href="/ps/2022/02/27/2022skku/">링크1</a>)과 (<a href="/hard-algorithm/2021/11/15/simd-in-ps/">링크2</a>)에서 실제 사례를 볼 수 있습니다.</p> <p><strong>선형대수학</strong> 관련 문제도 자주 보입니다. 가우스 소거법을 이용해 연립방정식을 풀어야 하는 문제(ex. 2020 서울 J)가 출제되기도 하고, 그래프 이론과 결합해서 그래프에서 특정 값을 구할 때도 사용합니다. 스패닝 트리의 개수를 구하는 Kirchhoff’s theorem, 최대 매칭의 크기를 구하는 Tutte matrix, DAG에서 정점이 중복되지 않는 경로를 만드는 경우의 수를 세는 LGV lemma 등이 대표적입니다.</p> <p><strong>오토마타</strong>는 오토마타 개념을 직접적으로 다루는 문제도 나오고, 그런 문제가 나오지 않더라도 DP의 상태 전이는 사실상 유항 상태 오토마타와 다름이 없고, KMP/Aho-corasick 같은 문자열 알고리즘은 오토마타 개념을 기본으로 깔고 시작합니다.</p> <p><strong>확률/랜덤 프로세스</strong>도 가끔씩 출제되고, 모르면 절대 못 푸는 유형으로 나오는 경우가 대부분입니다. 이전에 작성한 <strong>랜덤으로 문제 풀기</strong>라는 글을 읽어보는 것이 도움 될 것입니다. (<a href="/hard-algorithm/2020/03/23/random/">링크</a>)</p> <h2 id="대회-전략과-팀-워크">대회 전략과 팀 워크</h2> <h4 id="대회-전략의-필요성">대회 전략의 필요성</h4> <p>장홍준(hongjun7)님께서 startlink live에서 발표하신 <strong>Teamwork in Programming Contests</strong> 강연을 함께 보는 것을 추천합니다. (<a href="https://youtu.be/ECIhAfYeSIk">링크</a>) 저는 고등학생 때 이 영상을 보면서 팀 대회에 대한 꿈을 키워왔습니다.</p> <p>위에서도 언급했지만 ICPC는 3명이 1대의 컴퓨터를 사용해 문제를 해결하는 대회입니다. 당연히 개개인의 실력도 중요하지만, 어떤 상황에서 누가 키보드를 잡을지 결정하는 것도 매우 중요합니다. startlink live 강연에서는 $\max(A,B,C)$를 만드는 것보다는 $A+B+C$를 만들기 위해 노력해야 한다고 표현합니다.</p> <p>대회 전략의 목표는 다음과 같습니다.</p> <ul> <li><strong>낭비되는 시간 감소</strong></li> <li>서로의 강점을 파악</li> <li>서로의 약점을 보완</li> <li>위험 분산</li> </ul> <p>특히 낭비되는 시간을 줄이는 것이 매우 중요합니다. 낭비되는 시간을 줄이는 최상의 시나리오는 다음과 같습니다.</p> <ul> <li>A가 코딩하는 동안 B와 C는 풀이 고민</li> <li>A가 문제를 풀어서 B가 코딩 시작, C는 A와 풀이 토론</li> <li>B가 문제를 풀어서 C가 코딩 시작, A와 B는 각자 새로운 문제를 잡고 고민</li> <li>…</li> </ul> <p>낭비되는 시간 없이 잘 맞물려서 돌아간다는 것을 알 수 있습니다. 반면 최악의 시나리오는 정말 절망적입니다.</p> <ul> <li>A가 코딩하다가 말려서 디버깅 시작, B와 C는 풀이를 완성했지만 아직 A가 키보드를 차지하고 있는 상태</li> <li>A가 디버깅에 실패하고 B에게 키보드를 넘겨줌</li> <li>B가 코딩하는 중간중간에 A가 키보드를 뺏어서 다시 디버깅함(…)</li> <li>구현하지 못한 풀이가 3개 남은 채로 대회 종료</li> </ul> <p>키보드는 하나밖에 없는 희귀한 자원이기 때문에 효율적으로 사용해야 합니다. 문제를 푸는 과정을 생각해 보면 가장 먼저 풀이를 고민하고, 풀이를 찾으면 구현 방법을 고민하고, 그다음에 구현과 디버깅을 진행합니다.</p> <p>풀이를 고민하는 시간에는 키보드가 필요하지 않습니다. 또한 키보드를 잡고 있지 않은 다른 팀원과 토론도 할 수 있습니다.</p> <p>구현 방법을 고민할 때도 키보드가 필요하지 않습니다. 하지만 실제로 구현할 때는 키보드가 꼭 필요하기 때문에, 구현 방법을 잘 고민해서 구현 시간을 줄여야 합니다. 어떤 기능을 함수로 분리할지, 함수의 입력과 출력은 어떤 형식으로 할지 구상하고, 이를 바탕으로 코딩이 얼마나 걸릴지 예측하는 것이 좋습니다.</p> <p>디버깅은 키보드가 필요할 수도 있고 필요하지 않을 수도 있습니다. 디버깅은 뒤에서 다시 이야기합니다.</p> <h4 id="스코어보드-활용">스코어보드 활용</h4> <p>ICPC는 푼 문제 수가 같은 팀은 각 문제를 해결한 시간을 모두 더한 값을 기준으로 등수를 매기기 때문에 쉬운 문제부터 빨리 푸는 것이 좋습니다. 보통 많이 풀린 문제가 쉬운 문제이기 때문에 어떤 문제를 풀어야 할지 모르겠으면 스코어보드에서 많이 풀린 문제부터 풀면 됩니다. 이때 각 팀이 몇 번 시도해서 맞았는지도 알 수 있으므로, 문제를 한 번에 맞춘 팀이 없다면 실수하기 쉬운 문제이므로 구현하기 전에 풀이를 한 번 더 검증하고 구현할 때도 신중하게 코드를 짜는 것을 권장합니다.</p> <p>수상을 노리는 팀들은 추가적인 정보를 미리 파악해 놓는 것도 좋습니다. 저는 작년 ICPC를 준비할 때 다른 잘하는 팀이 잘 푸는 문제의 유형을 미리 파악해 놓았습니다. 만약 그 팀만 빨리 푼 문제가 있다면 그 문제를 건들지 않는 것이 좋을 수도 있습니다. 실제로 UCPC 2018(<a href="https://www.acmicpc.net/contest/spotboard/314">링크</a>)에 수학 올림피아드 문제가 그대로 나온 적이 있었는데, 1등 팀에는 IMO 국가대표 출신이 있어서 대회 시작 11분 만에 해결했지만, 두 번째로 푼 팀은 대회 시작 후 64분 뒤에 나왔었습니다.</p> <h4 id="디버깅">디버깅</h4> <p>디버거를 사용하는 것은 컴퓨터를 사용해야 하기 때문에 다른 팀원이 코딩할 기회를 뺏는 것입니다. 따라서 구현할 문제가 많이 밀려있을 때 디버깅이 오래 걸릴 것 같으면 비키는 것이 좋습니다. 최대한 디버거를 사용하지 않고 디버깅해야 하는데, ICPC는 코드 인쇄 요청을 할 수 있으므로 제출과 동시에 코드 인쇄 요청을 하는 팀들이 꽤 있습니다.</p> <p>인쇄된 코드를 보면서 디버깅할 일이 많으므로 눈으로 디버깅하는 연습을 꼭 해야 합니다. 논리가 잘못되지 않았는지, 코드로 잘못 옮기지 않았는지, 반복문 실행 도중에 invariant가 깨지지 않는지, 부등호 방향이나 i j k 같은 변수 이름을 잘못 쓰지 않았는지, 사용하지 않는 변수나 함수가 있는지 확인해야 합니다. 그리고 몇몇 사소한 실수는 의외로 다른 사람이 보면 잘 보일 수 있으므로 다른 팀원과 함께 디버깅하는 것도 좋은 방법입니다.</p> <h4 id="다른-팀원이-키보드를-잡고-있을-때">다른 팀원이 키보드를 잡고 있을 때</h4> <p>다른 팀원이 키보드를 잡고 있을 때 할 수 있는 행동은 다음과 같습니다.</p> <ul> <li>훈수 두기(페어 코딩)</li> <li>다른 문제 의사 코드 작성</li> <li>코드 인쇄해서 디버깅</li> <li>내 구현이 5~10분 이내로 끝날 것 같으면 키보드 뺏어서 구현하는 것도 고려</li> </ul> <h4 id="키보드를-잡은-사람이-없을-때">키보드를 잡은 사람이 없을 때</h4> <p>키보드를 잡고 있는 사람이 없을 때는 다양한 선택을 할 수 있습니다. 만약 검증하고 싶은 가설이 있는데 수학적으로 증명하기가 어렵다면 컴퓨터를 이용해 검증하는 것도 좋은 방법입니다. naive 코드를 작성해서 테스트해 볼 수 있습니다. 구현할 게 많아서 미뤄둔 문제를 조금씩 코딩할 수도 있고, 왜 틀리는지 모르겠는 코드가 있다면 스트레스 테스트를 작성해 볼 수도 있습니다.</p> <p>하지만 키보드가 비어 있다는 것을 의식해서 성급하게 구현하는 것은 별로 좋은 선택이 아닙니다. 항상 어떻게 구현할지, 구현하는 데 시간이 얼마나 걸릴지 생각한 다음 팀원들에게 예상 시간을 이야기하고 구현하는 습관을 들여야 합니다.</p> <h4 id="팀-전략의-분류">팀 전략의 분류</h4> <p>대부분의 팀 전략은 크게 개인플레이 위주의 팀(Solver * 3)과 매니저 중심의 팀(Solver * 2 + Manager)으로 분류할 수 있습니다.</p> <p>개인플레이 위주의 팀은 기본적으로 3명이 각자 문제를 풀다가 막히면 토론하는 방식입니다. 3명의 실력이 비슷하거나 분야가 겹치지 않을 때 사용하면 좋습니다. 매니저 중심의 팀은 두 명이 문제를 푸는 동안 다른 한 명이 문제 분배, 디버깅, 전략 수정 등 여러 가지 일을 맡아서 처리하는 방식입니다. 매니저 중심의 전략은 팀마다 세부 전략이 정말 많이 다르기 때문에 여러 팀의 실제 사례를 보면서 전략을 세우는 것이 좋습니다.</p> <p>2022년 서울 리저널 숭실대학교 NLP팀의 팀 전략은 아래에서 소개할 것이고, 그 밖에도 몇몇 팀들의 전략을 소개한 글을 링크합니다.</p> <ul> <li>서울대학교 MolaMola - 2017 서울 리저널 1등, 2017 쓰쿠바 리저널 3등, 2018 월드 파이널 5등 (<a href="https://zigui.tistory.com/19">링크</a>)</li> <li>고려대학교 1_Hoeaeng_2_Hawawang - 2020 서울 리저널 7등, 2021 월드 파이널 진출 (<a href="https://ryute.tistory.com/62">링크</a>)</li> <li>포스텍 000102 - 2022 서울 리저널 8등 (<a href="https://leo630.tistory.com/147">링크</a>)</li> <li>도쿄대학교 Cxiv-Dxiv - 2017 쓰쿠바 리저널 1등, 2018 월드 파이널 4등 (<a href="https://degwer.hatenablog.com/entries/2018/04/22">링크</a>, 일본어 주의)</li> </ul> <p>아래는 2022 서울 리저널 5등을 기록한 숭실대학교 NLP팀의 전략입니다.</p> <h4 id="실제-사례---팀원-구성">실제 사례 - 팀원 구성</h4> <p>팀원 구성은 다음과 같습니다. 팀원마다 장단점이 매우 뚜렷한 팀이라고 생각합니다.</p> <ul> <li>jhnah917 - BOJ 9000문제, solvedac 마스터, Codeforces 오렌지 <ul> <li>장점: 골드 1 이하의 쉬운 문제를 빠르게 해결, 구현 속도가 매우 빠름, 자료구조/그래프/기하 알고리즘을 많이 알고 있음</li> <li>단점: 수학을 잘 못함, 오래 고민해야 하는 문제를 잘 풀지 못함, 30분 안에 풀이를 못 찾으면 5시간 동안 못 찾는 경우가 많음, 한 번 말리면 크게 말림</li> </ul> </li> <li>edenooo - BOJ 3000문제, solvedac 루비3, Codeforces 레드 <ul> <li>장점: 문제 풀이 능력과 코딩 속도/정확도 모두 좋음, 팀원 중 수학을 가장 잘함, 대회 참가 경험이 매우 많음</li> <li>단점: 실수를 자주 함, 익숙하지 않은 분야가 꽤 있음</li> </ul> </li> <li>chansol - BOJ 1500문제, solvedac 다이아4, Codeforces 퍼플 <ul> <li>장점: 풍부한 개발 경험을 바탕으로 키보드가 비어있을 때 구현이 복잡한 문제나 스트레스 테스트 등을 잘 구현함</li> <li>단점: 다른 2명에 비해 문제를 많이 안 풀었음</li> </ul> </li> </ul> <p>팀원의 단점이 명확한 것은 안 좋은 요소이지만, 다행히 팀원의 장점이 서로 다르므로 다른 팀원의 단점을 잘 커버할 수 있었습니다. 특히 저는 BOJ, edenooo는 코드포스에서 주로 활동했는데, 주로 활동하는 사이트가 다르고 각자 사이트에서 최상위권이었기 때문에 두 명이 커버할 수 있는 문제의 범위가 매우 넓었습니다.</p> <p>커버할 수 있는 문제의 합집합이 큰 것은 장점이지만 교집합이 작은 것은 팀 구성 자체의 단점입니다. 한 명이라도 상태가 안 좋으면 타격이 큰데, 특히 저는 대회 시작 후 3시간이 지나면 퍼포먼스가 급격하게 떨어진다는 단점이 있습니다. 처음에는 이걸 고치려고 했지만 잘되지 않아서, 그냥 3시간 동안 최대한 많이 푸는 방향으로 팀 연습을 돌렸습니다. 실제로 2번을 제외한 모든 팀 연습은 3시간만 진행했습니다.</p> <h4 id="실제-사례---대회-초반--10--60분">실제 사례 - 대회 초반 (-10 ~ 60분)</h4> <p>대회 전략은 대회 시작 10분 전부터 시작합니다. 대회장에 들어가면 앞에 풍선이 배치되어 있는데, 풍선의 개수를 보면서 문제의 난이도를 유추했습니다. 대회 끝나고 스태프한테 물어보니 대회장에 꺼내놓은 풍선의 개수는 전부 똑같았다고 하던데… 뭐 아무튼 잘 맞았으니 다행입니다.</p> <p><img src="/img/icpc22-balloon.jpg" alt="" /></p> <p>일반적으로 제일 쉬운 문제는 앞쪽에 배치되어 있기 때문에 팀 연습을 할 때는 제가 ABCD, edenooo가 EFGH, chansol이 HIJK를 잡았습니다. 하지만 풍선을 보니 C부터 H까지가 전부 지뢰처럼 보여서(…) 제가 뒤쪽 4문제를 잡는 것으로 급하게 전략을 수정했습니다.</p> <p><img src="/img/icpc22-seat.jpg" alt="" /></p> <p>처음에는 위 사진처럼 컴퓨터가 가운데에 있고, 왼쪽 봉투 안에 계정 정보와 문제지가 들어있습니다. 하지만 예비소집 때 컴퓨터를 만져보면서 컴퓨터를 오른쪽에 배치하는 것이 최적이라는 결론을 내렸습니다. 따라서 대회가 시작하자마자 컴퓨터를 옮기는 과정도 미리 준비해갔습니다.</p> <p>저는 대회가 시작하자마자 쉬운 문제를 최대한 빨리 풀어야 하기 때문에 오른쪽에 앉아서 시작합니다. edenooo는 왼쪽 자리에서 시작했고, 대회가 시작되면 봉투를 뜯은 뒤 뒤쪽 4문제를 저에게 전달했습니다. chansol은 가운데에서 시작했고, 대회가 시작하면 로그인하고 CLion 환경설정까지 마친 다음에 컴퓨터를 오른쪽으로 이동시켰습니다. 그동안 저는 뒤에 있는 문제 4개를 모두 읽은 뒤, 쉬운 문제 3개를 찾아서 두 문제는 직접 해결하고 한 문제는 edenooo에게 전달했습니다.</p> <p>저와 edenooo가 초반 3문제를 해결하는 동안 chansol은 남은 문제 중 쉬운 문제를 찾아서 번역하고, 예제 설명까지 추가해서 코딩을 마치고 나오는 팀원들에게 전달했습니다. 첫 1시간은 이렇게 한 명이 문제를 분배하고, 나머지 두 명이 번갈아가면서 문제를 푸는 방식으로 진행합니다.</p> <p>30분 안에 해결할 수 있는 쉬운 문제를 모두 해결하면 대회 초반이 끝납니다. 지난 ICPC에서는 첫 1시간 동안 P5 이하인 5문제를 모두 해결했고, 이 시점에 4등을 기록했습니다.</p> <h4 id="실제-사례---대회-중반-60--180분">실제 사례 - 대회 중반 (60 ~ 180분)</h4> <p>중반부터는 긴 호흡을 갖고 고민해야 하는 문제를 해결해야 하는 단계입니다. 팀원의 장단점이 명확하기 때문에 문제를 잘 나눠 갖는 것이 중요합니다. 전형적이거나 어려운 배경지식을 사용해야 하는 문제는 주로 제가 가져가고, 오래 고민해야 하는 문제는 주로 edenooo가 가져갑니다. 그동안 chansol은 풀이 토론, 페어 코딩, 디버깅 등을 수행합니다.</p> <p>풀이가 나오면 키보드 스케줄링을 잘하면서 코딩을 시작하면 되고, 못 풀겠으면 문제를 교환하거나 토론해서 풀이를 찾아야 합니다. 대회 수상을 노리는 팀이라면 대회 중반에 잡는 문제는 어려운 문제가 아니기 때문에, 문제가 풀리지 않는다면 팀원 3명이 모두 붙어서 고민하는 한이 있더라도 꼭 풀어내야 합니다.</p> <p>여기까지 왔을 때 높은 등수에 올라왔다면 거의 다 완성되었다고 볼 수 있습니다. 지난 ICPC에서는 3시간 동안 플래티넘 이하의 모든 문제를 해결하고, D4인 C번도 해결해서 4등을 유지하고 있었습니다.</p> <h4 id="실제-사례---대회-후반-180--300분">실제 사례 - 대회 후반 (180 ~ 300분)</h4> <p>대회 중반을 특별히 말리는 것 없이 잘 넘겼다면, 마지막 2시간 동안에는 수상을 가르는 문제 하나를 풀면 됩니다. 이제 와서야 말할 수 있지만 저는 3시간이 지나면 퍼포먼스가 급격하게 떨어지기 때문에 사실상 edenooo를 믿고 기도하는 것이 가장 큰 전략이었습니다. chansol은 edenooo가 고민하는 문제를 함께 고민하거나 테스트 케이스를 제작하는 역할을 주로 수행했고, 저는 함께 토론하거나 다른 어려운 문제를 “이전에 풀어본 문제”로 바꿀 수 있을지 고민했습니다.</p> <p>지난 ICPC에서는 다행히 A를 풀어내서 5등으로 마무리했습니다.</p> <h4 id="오프라인-대회장">오프라인 대회장</h4> <p>위에서도 조금씩 언급했지만, 오프라인 대회장은 팀 연습과 환경이 다르기 때문에 여러 돌발상황이 발생할 수도 있고 불편한 점이 있을 수도 있습니다. 대회 전날 예비 소집이 본 대회와 동일한 환경에서 진행되기 때문에, 예비 소집을 하면서 최대한 변수를 통제할 수 있는 전략을 세워야 합니다.</p> <p>또한, 문제지와 팀 노트를 합하면 50페이지 정도 되는데, 대회 시작하고 2시간 정도 지나면 종이 50장이 섞여서 내가 풀고 있는 문제지를 찾지 못하는 참사가 발생할 수도 있습니다. 종이 정리하는 것도 신경 써야 합니다. 저는 푼 문제는 모두 바닥에 버리는 방식을 선택했습니다.</p> <h2 id="질의응답">질의응답</h2> <ul> <li>쉬운 문제를 잘 알아보는 방법 <ul> <li>ICPC 예선은 영어 지문만 제공되는 문제가 있고, 한글 지문이 함께 제공되는 문제도 있음</li> <li>한글로 된 3~4문제가 가장 쉬운 문제이므로 한글 문제부터 빠르게 해결하고, 그 이후로는 스코어보드를 따라가면 됨</li> </ul> </li> <li>권장 공부 시간 <ul> <li>고등학생 때는 평균적으로 하루에 8시간 정도 했고, 지금은 4시간 정도 하는 중</li> </ul> </li> <li>쉬운 문제를 빨리 푸는 방법 <ul> <li><del>브론즈 실버 골드 각각 2000개씩 풀면 됨</del></li> <li>서울 지역 대회에 나오는 골드 이하 문제는 대부분 전형적인 유형만 나오기 때문에 익숙해지면 빨리 풀 수 있음</li> </ul> </li> </ul>JusticeHui서론 지난 5월 4일에 성균관대학교에서 강연했던 것을 정리한 글입니다. 다음과 같은 내용을 다룹니다. 어떤 문제를 푸는 대회인가? 어떤 것에 초점을 맞춰서 공부해야 하는가? 최근 기출 문제에서 등장하는 알고리즘 전공과목과 연계되는 내용 대회 전략과 팀 워크2023 SCON 후기 - 모두가 즐거운 대회를 만드는 방법2023-05-21T00:00:00+00:002023-05-21T00:00:00+00:00https://justicehui.github.io/review/2023/05/21/scon<h2 id="서론">서론</h2> <p>끝이 보이지 않던 2023 SCON이 드디어 막을 내렸습니다!<br />지난 4년 동안 대회 출제&amp;검수는 50번도 넘게 해봤지만, 대회 운영의 처음부터 끝까지 관리한 것은 이번이 처음이었습니다. 시행착오가 많아서 힘들기도 했지만, 권한이 많은 만큼 제가 원하는 요소들을 자유롭게 대회에 넣을 수 있어서 즐거웠습니다.<br />개인적으로 이번 대회는 다른 것은 몰라도 <strong>1) 초보자들도 즐겁게 참가할 수 있는 대회</strong>, 그리고 <strong>2) 모두가 편안한 대회</strong>를 만들어서 참가자들이 프로그래밍 대회에 좋은 추억을 갖고 갔으면 하는 바람이 있었습니다. 이를 위해 많은 것들을 고려해야 했는데, 이번 글에서는 문제에 관한 이야기보다는 원활한 대회 진행을 위해 고려했던 것 위주로 풀어보려고 합니다.</p> <h2 id="야-우리-대회-개최하자">야 우리 대회 개최하자!</h2> <p>관심이 없는 분들은 다음 파트로 넘어가시면 됩니다. PC로 보는 경우 오른쪽 사이드바에서 문단을 건너뛸 수 있습니다.</p> <p>SCCC의 활동은 2020년부터 2021년까지 코로나19로 인해 멈춰있었습니다. 2022년에 SCCC 회장을 맡게 되면서 가장 중요하게 생각했던 것은 소모임의 상태를 2019년 이전으로 돌려놓는 것이었습니다. 2019년까지는 대회도 열고, 오프라인 스터디도 하고, 홈커밍이랑 MT도 가는 등 다양한 활동을 했었기 때문에 이런 활동들을 부활시키고 싶었습니다.</p> <p>하지만 2022년은 소모임 운영진이 1명이라고 봐도 될 정도로 대부분의 일을 저 혼자 처리했고, 학교/소모임 후원사와 대화하는 것과 온라인 스터디를 진행하는 것만으로도 너무 힘들었습니다. 그래서 대회는 2023년에 부회장을 하면서 회장과 함께 여는 것이 좋다고 판단했습니다. 홈커밍이랑 MT는 어느새 기억 속에서 사라졌습니다.</p> <p>다행히 올해 회장은 대회 운영 경험이 많은 <a href="https://www.acmicpc.net/user/chansol">chansol</a>이 잡았기 때문에 대회를 원활하게 운영할 수 있었습니다. 사실 chansol이 입학하자마자 회장으로 점 찍어놓은 상태였기 때문에, ICPC가 끝나자마자 회장을 넘겨주기 전인 11월부터 슬슬 대회를 준비하기 시작했습니다. 하지만 문제를 만들어야 하는 저, chansol, <a href="https://www.acmicpc.net/user/kyo20111">kyo20111</a>, <a href="https://www.acmicpc.net/user/edenooo">edenooo</a> 모두 <a href="https://2022w.ucpc.me/">BOJ 연말 대회와 신년 대회</a> 운영해야 하는 상황이어서 본격적인 작업은 Hello, BOJ 2023!이 끝난 이후인 1월 중순부터 시작했습니다.</p> <h2 id="목표">목표</h2> <p>사람뿐만 아니라 공부 분야에서도 첫인상은 매우 중요합니다. 예를 들어 출제 오류가 가득했던 <a href="https://www.acmicpc.net/jungol/2018/3">2018 한국정보올림피아드 예선</a>이 첫 알고리즘 대회였던 학생이 이후로 몇 년간 PS를 거들떠보지도 않았다는 이야기를 들은 적이 있고, 저만 하더라도 첫 CTF 대회였던 <a href="https://www.dailysecu.com/news/articleView.html?idxno=145171">2023 핵테온</a>의 운영을 보면서 크게 실망했었습니다. 저는 많은 사람이 알고리즘 문제 해결에 관심을 가졌으면 하는 바람이 있기 때문에 참가자들이 이번 대회에 즐겁게 참여하는 것이 중요하다고 생각했습니다.</p> <p><a href="https://www.acmicpc.net/category/318">UCPC</a>나 <a href="https://www.acmicpc.net/category/469">BOJ 연말 대회</a>처럼 고인물들이 많이 참가하는 대회를 준비할 때는 의도적으로 참가자들에게 심리전을 걸기도 합니다. 예를 들어 $O(N \log N)$ 시간에 풀 수 있는 그리디 문제의 입력 제한을 $N \leq 400$으로 준다던가, 의도적으로 예제를 약하게 주는 경우도 있습니다. 하지만 SCON은 최상위권 몇 팀을 제외하면 대부분의 참가자가 초보자이기 때문에 예제를 강하게 만들고 예제 설명을 친절하게 작성하는 등 최대한 문제 풀이를 찾는 것에만 집중할 수 있도록 많은 배려를 했습니다.</p> <p>대회 문제를 깔끔하게 만든 이후에도 고려할 것은 남아있었습니다. 고등학생 때 계절학교 모의고사와 국가대표 선발고사에 참여했을 때의 경험을 생각해 보면, 볶음밥에 제가 먹지 못하는 식재료가 들어가서 아예 먹지 못하고, 간식으로 준 샌드위치도 견과류가 들어가 있을까 봐 조교님들께 물어봤던 기억이 있습니다. 이렇게 운영진 입장에서는 사소하다고 생각할 수 있는 것도 어떤 참가자에게는 굉장히 큰 불편함으로 느껴질 수 있습니다. 모두가 편안한 대회를 만들고 싶다는 욕심이 있었기 때문에 제가 생각할 수 있는 범위 내에서는 최대한 참가자를 배려하려고 노력했습니다. 하지만 제가 만나는 사람들이 한정적이다 보니 고려하지 못한 부분이 있진 않을까 봐 대회를 진행하는 내내 불안했습니다. 다행히 제가 걱정하던 일은 벌어지지 않았고, 대회 끝나고 다들 즐거웠다고 말씀해 주셔서 뿌듯했습니다.</p> <p>참가자를 위한 목표 말고도 다른 목표도 있었습니다. 대회를 직접 운영해 보니, 과거 대회 자료를 참고하며 진행했음에도 불구하고 대회를 운영하는 것이 굉장히 힘들었습니다. 이번 대회에서 사용한 자료들을 문제가 생기지 않는 선에서 최대한 많이 공개해 다른 대회를 개최하시는 분들께 도움을 드리고자 합니다. 글 하단에서 공개된 자료를 확인할 수 있습니다.</p> <h2 id="고려해야-하는-것">고려해야 하는 것</h2> <h4 id="특별상">특별상</h4> <p>학교 내에서 유일하게 알고리즘 문제 해결을 다루는 단체인 SCCC가 컴퓨터학부 소모임이다 보니, 컴퓨터학부/소프트웨어학부를 제외한 다른 학부에는 PS를 처음 접해보는 학생이 굉장히 많습니다. 이 문제는 IT대학의 다른 교수님들도 인지하고 계신 문제이며, 소모임 담당 교수님께 대회 기획서를 제출했을 때 교수님께서 가장 먼저 말씀하신 내용 중 하나입니다.</p> <p>숭실대학교 IT대학는 컴퓨터학부, 소프트웨어학부, 글로벌미디어학부, 미디어경영학과, AI융합학부, 전자정보공학부로 구성되어 있습니다. 앞에 있는 4개의 학부는 주로 정보과학관을 사용하고, 다른 2개의학부는 주로 형남공학관을 사용합니다. IT대학 내의 모든 학부가 많이 참여할 수 있도록 학생회관, 정보과학관, 형남공학관에 여러 장의 포스터를 부착하고, 학부마다 최소 한 팀 이상 참가할 수 있도록 추가 TO를 마련했습니다.</p> <p>수상을 기대하지 않았더라도 대회에 와서 빈손으로 돌아가는 것은 슬픈 일이기 때문에, 이를 해결하기 위한 방법도 많이 고민했습니다. PS를 처음 접해보는 분들이 성취감을 느끼고 즐겁게 공부할 수 있는 계기가 되었으면 하는 마음에 학부별 1등 특별상과 1학년 1등 특별상을 추가했으며, 상품을 받지 못한 분들께도 다양한 간식과 나름(?) 대회 기념품인 명찰도 함께 제공했습니다.</p> <p>대회 후원사인 현대모비스에서 상품을 후원해 주셨습니다. 이 상품들은 성적과 관계 없이 특별한 기준으로 추첨하는 특별상 상품으로 증정했습니다. 특별상은 후원사 홍보 문제인 B번 문제를 꼭 읽어달라는 의미에서 A번 문제를 가장 늦게 푼 팀, 그리고 B번 문제에 시간을 많이 쏟아서 홍보의 효과를 높여준 것이 고맙다는 의미에서 B번 문제를 가장 많이 시도해서 푼 팀에게 수여했습니다. 후원사 관련 명분을 붙이긴 했지만, 사실은 하위권 팀에게도 상품을 주고 싶은 마음이 컸습니다.</p> <h4 id="음식물-알레르기">음식물 알레르기</h4> <p>저는 고등학생 때 일주일에 한 번은 급식으로 밥만 받아서 먹어야 할 정도로 못 먹는 음식이 많습니다. 음식을 주는 대회마다 알레르기 유발 물질을 알려주지 않는 것에 불만이 있었기 때문에, 제가 운영하는 대회는 이러한 불편함이 없길 바랐습니다.<br />참가자들에게 제공하는 문제지에 모든 간식의 알레르기 유발 물질과 혼입 가능한 물질을 함께 기재하는 방식으로 해결했습니다. 또한, 당류나 콜레스테롤 수치 등 영양 성분을 신경 써야 하는 참가자들도 있을 수 있기 때문에, 영양 성분표와 원재료가 궁금한 참가자는 운영진에게 문의하도록 안내했습니다.<br /><a href="https://github.com/ssu-sccc/2023scon/blob/master/statement.pdf">문제지</a> 6페이지에서 관련 내용을 확인할 수 있습니다.</p> <h4 id="운영진-인건비-지급-방식">운영진 인건비 지급 방식</h4> <p>돈을 받는 방법은 여러 가지가 있고, 사람마다 받아도 되는 방법과 받으면 안 되는 방법이 있습니다. 예를 들어 국가장학금과 같은 소득 분위에 따른 장학금을 받는 사람들은 소득이 안 잡히는 장학금으로 돈을 받는 것이 좋고, 다른 장학금을 지원받는 사람 중에는 오히려 장학금을 받는 것이 곤란한 경우도 있습니다. 이미 전액 장학금을 받는 사람들은 등록금 액수를 초과해서 장학금을 받을 수 있는지도 확인해야 합니다. 세금을 떼고 인건비를 지급하는 방법으로도 사업소득과 기타소득이 있는데, 특정 소득 분류로는 돈을 받을 수 없는 사람들도 있습니다.<br />인건비는 학교에서 지급하는 것이기 때문에 제가 왈가왈부할 수는 없지만, 스태프를 모집할 때 소득의 종류를 미리 알려주는 것은 할 수 있습니다. 혹시라도 나중에 인건비를 받았을 때 곤란한 상황이 발생하지 않도록 미리 지급 방식을 명시하고 스태프를 모집했습니다. 다음 대회를 위해 기록해 놓자면, 학교 재학생은 등록금 초과 수혜가 가능한 장학금, 외부 검수진은 8.8%를 원천징수 하는 기타소득으로 지급했습니다.</p> <h4 id="색약색맹">색약/색맹</h4> <p>국내에서 남성의 5~6%, 여성의 0.4% 정도가 색각이상 증상을 앓고 있다고 합니다. 문제 일러스트에 색깔이 들어가는 경우에는 색각이상자를 배려해서 제작해야 합니다. <a href="https://www.color-blindness.com/coblis-color-blindness-simulator/">Coblis</a>라는 서비스를 이용해 색각이상자에게 어떻게 보이는지 미리 확인하고, 색깔 외에도 모양으로 차이를 주는 방식으로 어느 정도 배려를 할 수 있었습니다. SCON과 비슷한 시기에 준비했던 다른 대회는 이런 방식으로 해결했고, SCON은 그냥 모든 일러스트를 흑백으로 통일하는 방식으로 해결했습니다.</p> <h4 id="초보자-배려">초보자 배려</h4> <p>다행히 선린인터넷고등학교 교내 대회인 천하제일 코딩대회를 2번 운영하면서(<a href="/review/2021/08/20/sunrin-icpc-2021/">#1</a>, <a href="/2022/07/08/sunrin-icpc-2022/">#2</a>) 초보자들이 많이 불편해하는 점들을 미리 파악했습니다. 이때의 경험을 바탕으로 다음과 같은 편의 사항을 제공했습니다.</p> <ul> <li>문제 난이도 커브<br />대회장에서 3시간 동안 한 문제만 풀고 집에 가는 건 전혀 즐겁지 않은 일입니다. 잘하는 팀들을 변별한 문제는 최소한으로 출제하고, 쉬운 난이도에 매우 많은 문제 수를 할당했습니다. 출제진이 예상한 난이도 기준으로 브론즈 3문제, 실버 3문제, 골드 2문제, 플래티넘 2문제를 출제했습니다. 처음에는 ICPC의 경향에 따라 C++과 Java로만 모든 문제를 해결할 수 있음을 보장하려고 했지만 결국 Python까지 모두 허용한 것도 약간의 배려… 라고 볼 수 있을 것 같습니다.</li> <li>수식 이해<br />“$i \ne j$ 이면 $A_i \ne A_j$ 이다.” 와 같은 수식이 익숙하지 않은 분들이 있습니다. 뒤에 “즉, $A$의 모든 원소는 서로 다르다.” 와 같은 문장을 덧붙이는 것으로 엄밀함과 친절함을 모두 챙겼습니다.</li> <li>코드 작성<br />입출력 양이 많아 빠른 입출력(Fast I/O)가 필요한 문제가 여러 개 있어서 이에 대한 안내와 템플릿 코드를 제공했습니다. 선린 대회에서는 64비트 정수형이 필요한 모든 문제에 힌트를 남겨놓았지만, SCON은 64비트 정수형이 필요하다는 정보가 문제 풀이와 연관된 경우가 있어서 문제에 적어주지 않았습니다.</li> <li>문제 독해<br />중고등학생 때를 생각해 보면 예제를 이해하는 것조차 힘들었던 적이 많이 있었습니다. 따라서 한눈에 예제를 이해할 수 없는 문제들은 최소한 한 개의 예제에 자세한 설명을 달아주었습니다.</li> <li>채점 진행도<br />UCPC와 같은 큰 대회는 채점 진행도를 보여주지 않습니다. 엄격한 채점을 위해서는 보여주지 않는 것이 맞다고 생각하지만, 채점 진행도를 보여주지 않으면 대회 참가 경험이 적은 참가자들이 혼란을 겪을 수 있기 때문에 보여주는 것으로 결정했습니다.</li> </ul> <h4 id="사진-촬영">사진 촬영</h4> <p>대회 진행 도중에 사진 촬영을 하고 온라인에 공개할 예정이기 때문에 참가자들에게 미리 동의받았습니다. 가장 좋은 방법은 팀마다 동의 여부를 조사해서 동의한 팀들만 사진을 남겨주는 것이지만, 학교 플랫폼에서 이뤄지는 참가 신청 양식을 제가 수정하는 것이 어렵기 때문에 동의만 받았습니다. 다음 대회에서는 구글 폼을 함께 받는 것이 좋을 것 같습니다.</p> <h4 id="저작권">저작권</h4> <p>문제 일러스트를 제작할 때 글꼴이나 클립아트의 저작권을 고려하는 것이 귀찮아서 모든 그림을 <a href="https://ko.overleaf.com/learn/latex/TikZ_package">tikz</a>로 그렸습니다.</p> <p>-</p> <p>엄격함과 좋은 경험을 주는 것 사이에서 줄 타는 것이 쉽지 않았습니다. 64비트 정수형 사용 안내는 문제 풀이에 간접적인 힌트가 될 수 있기 때문에 의도적으로 알려주지 않았고, 채점 진행도는 대회의 공정성을 해치지 않는다고 판단해서 보여주는 것으로 결정했습니다.</p> <h2 id="다음-대회에서-개선할-점">다음 대회에서 개선할 점</h2> <p>이 밖에도 인지는 하고 있었지만 제가 너무 안일하게 생각했거나 뒤늦게 떠올라서 미처 준비할 시간이 없었던 요소들도 있었습니다. 또는 참가자에게 직접적으로 영향이 가지는 않지만 수정하면 좋았을 것 같은 점들도 많이 보였습니다. 다음 대회에서는 꼭 반영하도록 노력하겠습니다.</p> <h4 id="휠체어-이동">휠체어 이동</h4> <p>학교에 계단이 정말 많습니다. 그래도 다들 학교 재학생이니 정보과학관까지 알아서 잘 찾아올 것이라 생각했지만, 생각해 보니 IT대학 소속 학부 중 정보과학관을 사용하지 않는 학부도 있었습니다. 원래라면 경사로와 엘리베이터만 이용해 대회장까지 오는 방법도 같이 안내했어야 했는데, 학교 재학생이라는 것을 믿고 너무 안일하게 있었습니다. 이 점은 다음 대회에서 꼭 보완하려고 합니다.</p> <h4 id="풍선-공포증-balloonphobia">풍선 공포증 (Balloonphobia)</h4> <p>프로그래밍 대회는 문제를 맞힐 때마다 풍선을 달아주는 전통이 있습니다. 하지만 풍선을 무서워하는 분들도 있기 때문에 풍선을 참가자와 먼 곳에 배치하거나 높이 배치하는 등의 배려가 필요합니다. 이런 분들이 있다는 것은 예전에 다른 대회를 운영하면서 들은 적이 있지만, 정작 이 대회를 운영할 때는 대회 당일에 생각나서 대응하지 못했습니다.</p> <h4 id="2인-팀-관련">2인 팀 관련</h4> <p>2019년에는 2인 팀과 3인 팀을 모두 허용했지만, 이번 대회는 3인 팀만 허용했습니다. 생각하지 못했던 부분인데, 3명을 모으지 못해서 대회 참가 신청을 하지 못했다는 이야기가 들리는 것을 보면 2인 팀도 허용하는 것도 고려해 보면 좋을 것 같습니다.</p> <h4 id="참가-신청-기간">참가 신청 기간</h4> <p>참가 신청 마감을 일요일로 설정했었는데, 이러면 안 됐습니다. 참가 신청은 마지막 날에 많이 몰리고 당연히 문의도 마지막 날에 많이 들어옵니다. 하지만 저는 참가 신청이 이뤄지는 학교 플랫폼을 모르기 때문에 문의가 와도 답변을 할 수 없었습니다. 다음 대회에서는 꼭 참가 신청 마감 기한을 평일 학교 직원 퇴근 전으로 잡아야겠습니다.</p> <h4 id="그리고-또">그리고 또…</h4> <p>가장 확실한 방법은 참가자들에게 편의를 봐주었으면 좋겠다는 것들을 설문으로 조사하는 것일 테지만, 재학생인 제가 이런 민감한 정보를 수집하는 것은 좋지 않다고 판단했기 때문에 운영진들끼리만 머리를 굴려서 생각할 수 있는 모든 경우를 고려하는 방향으로 진행했습니다.</p> <p>참가자들을 편하게 해주려고 하다 보니 운영진들이 죽어 나갔습니다. 스태프를 더 뽑아서 함께 일하는 방법도 생각을 해봤지만, 개인 정보를 다루는 작업이 많아서 한정된 인원들끼리만 작업했습니다. 다음 대회에서는 개인 정보를 다루지 않는 작업을 최대한 분리해서 스태프들과 함께 일하는 것이 좋을 것 같습니다. 이렇게 대회를 바닥부터 운영하는 것은 처음인지라 많이 미숙했습니다.</p> <p>최근에 <a href="https://docs.google.com/document/d/13_fai5iy-deR47-vBEfkMIVSEitCDUs6gT3MjylhnSo/edit#heading=h.23f1blhwd0oj">IOI 2022 HTC Report</a>를 읽었습니다. 참가자들에게 나눠준 5가지 색깔 카드(간식, 연습장, 화장실, 물, 컴퓨터 교체 요구)가 좋아 보이던데 다음 대회에 도입하는 것을 고려해 봐야겠습니다.</p> <h2 id="출제검수">출제/검수</h2> <p>대회를 열기 위해서는 문제가 있어야 하고, 문제를 만들기 위해서는 출제자와 검수자가 필요합니다. 다른 대회를 보면 검수진을 선착순으로 모집하는 대회도 많이 있던데, 사실은 출제진을 구성하는 것보다 중요한 것이 검수진을 구성하는 것입니다. 출제진과 검수진을 모집한 과정을 자세하게 풀어보려고 합니다.</p> <p>출제진을 구하는 것은 쉬웠습니다. 처음에는 8~12문제 정도의 대회를 기획하고 있었고, 이 정도의 문제를 만들기 위해서는 3~5명 정도의 출제자가 있는 것이 좋을 것 같다고 생각했습니다. 마침 숭실대학교 재학생 중 ICPC 수상자가 4명 있어서 4명을 모두 출제진으로 끌어들이고, 대회 참가 자격를 <strong>ICPC Asia Seoul Regional Contest 수상 경험이 없는 자</strong>로 결정했습니다. 과거 대회를 보면 본선 진출자도 참가를 막았던 적도 있는 것 같은데, 2023 SCON은 코로나19 이후로 4년 만에 열리는 교내 대회이기 때문에 참가 자격을 널널하게 정했습니다.</p> <p>검수진을 정할 때는 매번 정말 많이 고민합니다. 이번 대회는 검수비 예산을 3명분만 잡아놓았고, 심지어 IT대학 측에서는 대학생이나 대학원생을 요구해서 더 많이 고민했습니다.</p> <p>저는 대회 난이도와 참가자, 그리고 문제 스타일에 따라 검수진을 다르게 구성합니다. 상수 커팅을 고려해서 세팅한 문제가 있으면 상수 커팅을 잘하는 검수자를 섭외하고, 문제를 많이 푼 사람이 참여하는 대회는 기존에 비슷한 문제가 출제되었는지 확인하기 위해 BOJ 랭커를 섭외합니다. 올솔브 방지 문제를 내거나 계산 기하 문제 등 다른 검수자들이 검수하지 못할 것 같은 문제가 있으면 그 한 문제를 위한 검수자를 섭외하기도 합니다.</p> <p>다행히 이번 대회는 쉬운 대회를 지향하고 상수 커팅을 고려하지 않아도 돼서 특정 역할을 요구하는 검수진을 모집할 필요는 없었습니다. 이번 대회의 검수진으로는 깔끔한 문제 지문을 만들기 위해 지문 위주로 검수할 <a href="https://www.acmicpc.net/user/ryute">ryute</a>, 모든 문제를 풀어보면서 수정해야 할 점을 알려줄 <a href="https://www.acmicpc.net/user/junseo">junseo</a>, 마지막으로 문제 지문과 풀이, 그리고 $\LaTeX$ 조판 등 대회 운영 전반에 대해 조언을 해줄 <a href="https://www.acmicpc.net/user/cologne">cologne</a>를 섭외했습니다. 세 분 모두 제가 기대한 것보다 더 열심히 꼼꼼하게 문제를 검수해 주셨습니다. 모두 감사합니다.</p> <p>제가 출제 총괄을 담당하긴 했지만, 출제자 4명 모두 PS 실력과 대회 운영 경험 모두 고일 대로 고인 사람들이라 알아서 잘할 것이라 믿고 터치하지 않았습니다. 실제로 진짜 잘했기도 하고요. 사용되는 알고리즘이 많이 겹치면 문제 몇 개를 버리고 새로 만들려고 했지만, 다행히 그런 일은 발생하지 않았습니다.</p> <p>문제 지문과 풀이 슬라이드는 <a href="https://www.overleaf.com/">Overleaf</a>, 채점 데이터와 솔루션 코드는 <a href="https://polygon.codeforces.com/">Codeforces Polygon</a>을 이용해 관리했습니다. 동일한 정보를 두 곳 이상에서 관리하면 변경 사항을 반영하고 추적하기 어렵기 때문에, 지문과 데이터가 모두 완성된 다음에 대회 3일 전에 <a href="https://stack.acmicpc.net/">BOJ Stack</a>으로 옮겼습니다.</p> <p>Overleaf는 유료 플랜을 사용하지 않으면 프로젝트 공유를 1명까지밖에 할 수 없고, 저는 무료 플랜을 사용하기 때문에 프로젝트를 공유할 때 링크를 이용해서 공유해야 했습니다. 출제진과 운영진 모두 서로 아는 사람이고 같이 대회도 여러 번 운영해 봤기 때문에 안심하고 링크 공유를 했지만, 혹시라도 사고가 발생하진 않을까 조금은 불안하기도 했습니다. <a href="https://blog.shift.moe/2020/10/21/ucpc-2020/">UCPC 2020</a>에서는 self-hosted Overleaf에서 작업했었는데, 다음에도 대회를 운영하게 된다면 이것을 고려해 보는 것도 좋을 것 같습니다.</p> <p>Overleaf에서 $\LaTeX$로 작성한 문제를 BOJ Stack으로 옮기는 것도 매우 귀찮은 작업인데, <a href="https://solved.ac">solved.ac</a>의 개발자이신 <a href="https://shiftpsh.com">shiftpsh</a>님께서 <a href="https://solved-ac.github.io/boj-description-converter/">BOJ Stack 디스크립션 툴</a>을 개발해 주셔서 잘 사용했습니다. 감사합니다.</p> <p>풀이 슬라이드는 shiftpsh님께서 제작하신 <a href="https://github.com/ucpcc/2020-solutions-theme">UCPC 2020 solutions theme</a>, 문제지는 Codeforces Polygon에서 기본으로 제공해 주는 <a href="https://github.com/GassaFM/olymp.sty">GassaFM/olymp.sty</a>을 개조한 것을 사용했습니다.</p> <h2 id="노동">노동</h2> <p>저는 chansol과 함께 대회 운영에서의 모든 의사 결정에 참여했습니다. 또한 예산안 작성, 문제 출제/검수 총괄, 스태프 관리, 3문제 출제, 모든 문제의 모든 언어(C++/Java/Python) 풀이 코드 작성 및 검수, 문제지 제작, 풀이 슬라이드 제작, 문제 일러스트 제작을 담당했습니다. 이 밖에도 명찰 제작, 문제지 봉인과 같은 단순 반복 노동도 하고, 대회 당일에는 풍선 배달, SCCC 홍보, 스코어보드 오픈까지 진행했습니다.</p> <p>SCON과 비슷한 시기에 다른 대회도 함께 준비했었는데, 대회가 다가올수록 두 대회 모두 신경 쓸 것들이 정말 많아져서 정신이 없었습니다. 머리도 힘들고 몸도 힘들고… 심지어 5/8에는 코로나 확진까지 되어서 정말 많이 힘들었습니다. 그래도 격리 기간이 일주일이나 되는 덕분에 이틀 정도 아팠던 것을 제외하면 학교에 안 가고 하루 종일 대회 준비에 집중할 수 있는 좋은 기회가 되었습니다.</p> <p>더 자세하게 쓰면 너무 재미없을 것 같아서 더 작성하지는 않겠습니다.</p> <h2 id="sccc에-대한-이야기">SCCC에 대한 이야기</h2> <p>코로나19 이전에는 SCCC에서 매년 대회를 개최하고, 나름대로 출제 프로세스의 인수인계도 잘 이루어졌던 것으로 알고 있습니다. 하지만 2020년부터 소모임의 모든 활동이 멈추게 되면서 모든 것이 끊어졌습니다. 다행히 지난 몇 년 동안 특기자 전형 덕분에 정신 나간 고인물 몇 명이 들어와서 올해 대회를 개최하는 것은 성공했지만, 당장 내년부터는 다들 졸업하거나 바빠질 것 같아서 대회 개최를 지속하는 것이 쉽지 않아 보입니다. 새로운 고인물이 매년 들어온다는 보장도 없고요.</p> <p>내년까지 제가 많은 부분을 담당해서 운영하고 그다음에 졸업해 버리면 인수인계 같은 것이 전혀 이루어지지 않게 되는 상황입니다. 그래서 여름방학에 SCCC에서 문제 출제하는 방법에 대해 강의하고, 모의대회를 개최해 보면서 다음 대회를 위한 빌드업을 해보려고 합니다. 그래도 소모임에 열심히 PS를 하는 후배들이 여러 명 있기 때문에 인수인계만 잘 이루어진다면 앞으로도 계속 좋은 대회를 열 수 있을 것 같습니다.</p> <p>여러 동아리의 운영진들과 이야기해 보니, 후배들을 가르쳐도 열심히 하지 않아서 허탈하다고 이야기하는 사람들이 많습니다. 저도 그렇게 느껴서 많이 고민했던 적도 있지만, 지금은 동아리 들어와서 자신이 PS와 맞지 않고 재능이 없다는 것을 깨닫는 것만으로도 충분하다고 생각하고 있습니다. 중간중간에 잘하는 후배들을 몇 명 발견하면 더 좋고요.</p> <p>잘하고 싶다고 이야기하면서 하루에 한 문제도 안 푸는 것을 보면 어이없고, 잘 이해하지도 못했으면서 질문은 절대 안 하는 것을 보면 속이 터지긴 하지만, 그래도 문제 열심히 풀고 혼자 다른 것들을 더 찾아서 공부하는 학생 몇 명 보는 맛에 동아리를 운영하고 있습니다. PS가 적성에 맞지 않는데 꼬박꼬박 스터디 참석해서 자리에 앉아있는 것만으로도 그 학생들 나름대로 힘들 것이라고 생각합니다.</p> <p>1학기의 가장 큰 행사인 SCON이 끝났으니 조금 쉬고 다시 힘내서 여름방학 스터디를 준비해야겠습니다.</p> <h2 id="대회-운영-자료-공개">대회 운영 자료 공개</h2> <p><a href="https://github.com/ssu-sccc/2023scon">https://github.com/ssu-sccc/2023scon</a>에서 확인할 수 있습니다. 지금은 제가 갖고 있는 파일인 풀이 슬라이드 프로젝트, 문제지 프로젝트, 현장 스태프 매뉴얼을 올려놓았고, 추후 다른 파일이 더 추가될 수 있습니다. 2023 SCON에서 사용한 방식이 꼭 좋은 방식은 아니지만, 그래도 다른 대회를 운영하시는 분들께서 초기 기획을 세울 때 도움이 되었으면 좋겠습니다.</p> <h2 id="마무리">마무리</h2> <p>고등학교 2학년 때 대회 열어보겠다고 객기부리던 것과 3학년 때 UCPC Call for Tasks에 문제 제출하고 조마조마하며 기다리던 것이 엊그제 같은데, 이제는 정말 대회 운영과 관련된 대부분의 업무를 처리할 수 있을 정도로 성장했습니다. 문제 출제, 검수, 후원사 연락, 운영, 서버 관리까지 해봤고, 안 해본 것은 장소 대관 정도밖에 남지 않은 것 같습니다.</p> <p>4년 전, 수능을 100일 앞둔 시점에 제 첫 대회 개최를 도와주고 지금도 문제 검수가 필요할 때마다 흔쾌히 달려와 주는 Ryute님, UCPC, SPC, SUAPC 등 다양한 대회의 운영 경력을 쌓을 기회를 주신 shiftpsh님을 비롯한 서강대 분들, BOJ 연말 대회마다 저를 불러주신 leejseo님, 그리고 최고의 선배 wookje님께 정말 감사드립니다. 사실 <a href="/review/2022/03/27/skh/">숭고한 개최 후기</a> 복붙입니다. 죄송ㅎㅎ</p> <p>학교와의 소통을 혼자서 담당해 주고 제가 고려하지 못한 부분까지 세심하게 관리해 준 chansol, 좋은 문제를 제공해 준 멋진 선배 kyo20111, edenooo, 문제뿐만 아니라 대회 운영 전반에 대해 많은 조언을 해주신 검수진 cologne, junseo, ryute가 없었으면 대회 개최는 불가능했을 것입니다. 정말 감사합니다. 대회 당일 이른 시간부터 나와서 함께 고생한 스태프들과 스태프 모집 글을 홍보해 주신 분들께도 이 글을 빌려 감사의 말씀 드립니다.</p> <p>다음에는 더 멋진 대회로 돌아오겠습니다.</p> <p>끝!</p>JusticeHui서론 끝이 보이지 않던 2023 SCON이 드디어 막을 내렸습니다!지난 4년 동안 대회 출제&amp;검수는 50번도 넘게 해봤지만, 대회 운영의 처음부터 끝까지 관리한 것은 이번이 처음이었습니다. 시행착오가 많아서 힘들기도 했지만, 권한이 많은 만큼 제가 원하는 요소들을 자유롭게 대회에 넣을 수 있어서 즐거웠습니다.개인적으로 이번 대회는 다른 것은 몰라도 1) 초보자들도 즐겁게 참가할 수 있는 대회, 그리고 2) 모두가 편안한 대회를 만들어서 참가자들이 프로그래밍 대회에 좋은 추억을 갖고 갔으면 하는 바람이 있었습니다. 이를 위해 많은 것들을 고려해야 했는데, 이번 글에서는 문제에 관한 이야기보다는 원활한 대회 진행을 위해 고려했던 것 위주로 풀어보려고 합니다.백준17674 특별관광도시2023-02-26T00:00:02+00:002023-02-26T00:00:02+00:00https://justicehui.github.io/joisc/2023/02/26/BOJ17674<h3 id="문제-링크">문제 링크</h3> <ul> <li>http://icpc.me/17674</li> </ul> <h3 id="문제-출처">문제 출처</h3> <ul> <li>2018/2019 JOISC Day3 1번</li> </ul> <h3 id="사용-알고리즘">사용 알고리즘</h3> <ul> <li>트리 DP</li> <li>그리디</li> <li>센트로이드</li> </ul> <h3 id="시간복잡도">시간복잡도</h3> <ul> <li>$O(N \log^2 N)$</li> </ul> <h3 id="풀이">풀이</h3> <p>선택되지 않은 간선의 가중치 합을 최소화하는 문제입니다. 반대로 선택된 간선의 가중치 합을 최대화하는 문제로 생각해서 해결해 봅시다.</p> <h4 id="subtask-2-q--1-e_1--1-7점">Subtask 2. $Q = 1, E_1 = 1$ (7점)</h4> <p>선택한 정점이 트리의 루트라고 생각합시다. 루트로 올라가는 간선의 가중치를 최소화하는 문제입니다.<br /> Tree DP를 이용하면 $O(N)$ 전처리를 통해 각 정점이 루트인 경우에 대한 답을 상수 시간에 구할 수 있습니다. 이 문제에 도전할 정도의 실력이라면 다들 알고 있을 것이라 믿습니다.</p> <p><a href="https://oj.uz/submission/702675">코드</a></p> <h4 id="subtask-4-n-leq-2000-30점">Subtask 4. $N \leq 2\,000$ (30점)</h4> <p>루트를 고정하는 Subtask 2의 아이디어는 그대로 가져갑니다. 추가로, 루트 정점과 리프 정점만 선택해도 정답을 찾을 수 있다는 점을 관찰해야 합니다. 리프 정점이 아닌 두 정점을 선택하는 것이 최적이라면, 자식 정점을 대신 선택해도 같거나 더 좋은 답을 낼 수 있다는 점을 생각해 보면 좋습니다.</p> <p>루트가 고정된 상태에서 정점을 선택하는 것은 세 가지 경우로 나눌 수 있습니다.</p> <ol> <li>루트만 선택 (정점 1개 선택)</li> <li>루트 정점을 선택하고 리프 정점을 1개 이상 선택</li> <li>루트 정점을 선택하지 않고 리프 정점을 2개 이상 선택</li> </ol> <p>세 가지 경우 모두 루트로 향하는 간선이 전부 선택된다는 점을 관찰할 수 있습니다. 단, 세 번째 경우에서는 두 개 이상의 서로 다른 서브 트리에서 리프를 선택해야 합니다. 2, 3번 경우에서 어떤 간선들이 추가로 선택되는지 알아봅시다.</p> <p>두 번째 경우부터 살펴보겠습니다. 두 번째 경우에서는 루트에서 선택한 정점으로 가는 간선이 추가로 선택됩니다. 따라서 이 경우에는 루트가 있는 트리에서 정점 $K$개를 선택했을 때 루트에서 선택한 정점으로 가는 간선들의 가중치 합을 최대화하면 됩니다. 이런 문제는 DP 또는 그리디를 이용해 해결할 수 있습니다.</p> <p>$D(v, k)$를 $v$를 루트로 하는 서브 트리에서 리프를 $k$개 선택했을 때의 최댓값이라고 정의합시다. DP를 MCMF로 모델링할 수 있기 때문에 $D(v, \ast)$는 볼록합니다. 따라서 $D(u, \ast)$와 $D(v, \ast)$를 $D(r,k_1+k_2) \leftarrow D(u,k_1) + D(v,k_2)$와 같이 합칠 때 기울기가 큰 것부터 하나씩 끼워넣으면 됩니다. 우선순위 큐와 Small to Large를 이용해 $O(N \log^2 N)$에 $D(root, \ast)$를 모두 구할 수 있습니다.</p> <p>이 DP 풀이를 응용하면 그리디 기법을 이용해 $O(N \log N)$ 시간에 해결할 수도 있습니다. $D(v, k) - D(v, k-1)$은 $k$번째로 정점을 선택했을 때 추가되는 경로를 의미합니다. $D(v, \ast)$에 저장되어 있는 경로 중 $v$보다 위로 확장될 수 있는 경로는 $D(v, 1) - D(v, 0)$ 뿐이고, 다른 나머지 경로들은 $v$ 밑에서 끊어져서 더 이상 연장되지 않습니다.<br /> 끊어진 경로들은 굳이 Small to Large에서 주고 받을 필요가 없고, 전역에 선언되어 있는 우선순위 큐 하나에서 모두 관리해도 무방합니다. 즉, $D(v, \ast)$에서 $v$ 밑에 있는 모든 경로를 관리하는 대신 가장 긴 경로 하나만 관리하고, 다른 나머지 경로는 전역에 있는 우선순위 큐에서 관리할 수 있습니다. 이때의 시간 복잡도는 $O(N \log N)$입니다.<br /> 한국에서는 <a href="https://www.acmicpc.net/problem/8987">KOI 2013 고등부 4번. 수족관 3</a>의 풀이로도 잘 알려져 있습니다.</p> <p>따라서 두 번째 경우는 $O(N \log N)$ 시간에 처리할 수 있습니다.</p> <p>이제 세 번째 경우를 살펴보겠습니다. 세 번째 경우에서는 두 개 이상의 서로 다른 서브 트리에서 리프 정점을 선택해야 합니다. 한쪽에서만 정점을 뽑으면, 그 서브 트리에서 루트로 올라가는 간선이 선택되지 않을 수 있기 때문입니다.<br /> 사실 세 번째 경우도 두 번째 경우와 비슷하게 처리할 수 있습니다. 각 경로가 어떤 서브 트리에서 유래했는지 함께 저장한 다음, 가장 큰 경로와 다른 서브 트리에서 유래한 가장 큰 경로를 강제로 포함시키면 됩니다. 따라서 세 번째 경우도 $O(N \log N)$ 시간에 처리할 수 있습니다.</p> <p>루트가 고정되어 있을 때 $O(N \log N)$ 만큼 걸리므로 전체 시간 복잡도는 $O(N^2 \log N)$입니다.</p> <p><a href="https://oj.uz/submission/702682">코드</a></p> <h4 id="subtask-6-100점">Subtask 6. (100점)</h4> <p>Subtask 4의 풀이에 Centroid Decomposition을 적용하면 $O(N^2 \log N)$을 $O(N \log^2 N)$으로 줄일 수 있습니다.<br /> Subtask 4 코드에 센트로이드 관련 처리 부분만 추가하면 됩니다.</p> <h3 id="전체-코드">전체 코드</h3> <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">Q</span><span class="p">,</span> <span class="n">Sum</span><span class="p">,</span> <span class="n">C1</span><span class="p">,</span> <span class="n">C</span><span class="p">[</span><span class="mi">202020</span><span class="p">],</span> <span class="n">R</span><span class="p">[</span><span class="mi">202020</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="n">ll</span><span class="p">,</span><span class="n">ll</span><span class="o">&gt;&gt;</span> <span class="n">G</span><span class="p">[</span><span class="mi">202020</span><span class="p">];</span> <span class="kt">int</span> <span class="n">S</span><span class="p">[</span><span class="mi">202020</span><span class="p">],</span> <span class="n">U</span><span class="p">[</span><span class="mi">202020</span><span class="p">];</span> <span class="kt">int</span> <span class="nf">GetSize</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">b</span><span class="o">=-</span><span class="mi">1</span><span class="p">){</span> <span class="n">S</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">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">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="n">i</span> <span class="o">!=</span> <span class="n">b</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">U</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">v</span><span class="p">]</span> <span class="o">+=</span> <span class="n">GetSize</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="k">return</span> <span class="n">S</span><span class="p">[</span><span class="n">v</span><span class="p">];</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">GetCent</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">n</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</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="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">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="n">i</span> <span class="o">!=</span> <span class="n">b</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">U</span><span class="p">[</span><span class="n">i</span><span class="p">]</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="mi">2</span> <span class="o">&gt;</span> <span class="n">n</span><span class="p">)</span> <span class="k">return</span> <span class="n">GetCent</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="n">v</span><span class="p">);</span> <span class="k">return</span> <span class="n">v</span><span class="p">;</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">TreeDP</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">b</span><span class="o">=-</span><span class="mi">1</span><span class="p">,</span> <span class="n">ll</span> <span class="n">up</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">ll</span> <span class="n">dw</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">i</span><span class="p">,</span><span class="n">w</span><span class="p">]</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="n">i</span> <span class="o">==</span> <span class="n">b</span><span class="p">)</span> <span class="n">C1</span> <span class="o">+=</span> <span class="n">w</span><span class="p">,</span> <span class="n">up</span> <span class="o">+=</span> <span class="n">w</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">dw</span> <span class="o">-</span> <span class="n">up</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">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="n">i</span> <span class="o">!=</span> <span class="n">b</span><span class="p">)</span> <span class="n">TreeDP</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">up</span><span class="p">,</span> <span class="n">dw</span><span class="o">+</span><span class="n">w</span><span class="p">);</span> <span class="p">}</span> <span class="n">ll</span> <span class="nf">CostToRoot</span><span class="p">(</span><span class="kt">int</span> <span class="n">root</span><span class="p">){</span> <span class="k">return</span> <span class="n">C1</span> <span class="o">+</span> <span class="n">C</span><span class="p">[</span><span class="n">root</span><span class="p">];</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="n">ll</span><span class="p">,</span><span class="n">ll</span><span class="o">&gt;&gt;</span> <span class="n">PathsFromRoot</span><span class="p">(</span><span class="kt">int</span> <span class="n">root</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="n">ll</span><span class="p">,</span><span class="n">ll</span><span class="o">&gt;&gt;</span> <span class="n">paths</span><span class="p">;</span> <span class="n">function</span><span class="o">&lt;</span><span class="n">ll</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="kt">int</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">dfs</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">st</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">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">ll</span> <span class="p">{</span> <span class="n">ll</span> <span class="n">mx</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">i</span><span class="p">,</span><span class="n">w</span><span class="p">]</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="n">i</span> <span class="o">==</span> <span class="n">b</span> <span class="o">||</span> <span class="n">U</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="k">continue</span><span class="p">;</span> <span class="n">ll</span> <span class="n">nxt</span> <span class="o">=</span> <span class="n">dfs</span><span class="p">(</span><span class="n">st</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">w</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">nxt</span> <span class="o">&gt;</span> <span class="n">mx</span><span class="p">)</span> <span class="n">swap</span><span class="p">(</span><span class="n">mx</span><span class="p">,</span> <span class="n">nxt</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="n">mx</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="n">paths</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">nxt</span><span class="p">,</span> <span class="n">st</span><span class="p">);</span> <span class="p">}</span> <span class="k">return</span> <span class="n">mx</span><span class="p">;</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">G</span><span class="p">[</span><span class="n">root</span><span class="p">])</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">U</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="n">paths</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">dfs</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">root</span><span class="p">)</span> <span class="o">+</span> <span class="n">w</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span> <span class="k">return</span> <span class="n">paths</span><span class="p">;</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">Go</span><span class="p">(</span><span class="kt">int</span> <span class="n">root</span><span class="p">){</span> <span class="n">root</span> <span class="o">=</span> <span class="n">GetCent</span><span class="p">(</span><span class="n">root</span><span class="p">,</span> <span class="n">GetSize</span><span class="p">(</span><span class="n">root</span><span class="p">));</span> <span class="n">U</span><span class="p">[</span><span class="n">root</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">ll</span> <span class="n">to_root</span> <span class="o">=</span> <span class="n">CostToRoot</span><span class="p">(</span><span class="n">root</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="n">ll</span><span class="p">,</span><span class="n">ll</span><span class="o">&gt;&gt;</span> <span class="n">paths</span> <span class="o">=</span> <span class="n">PathsFromRoot</span><span class="p">(</span><span class="n">root</span><span class="p">);</span> <span class="n">sort</span><span class="p">(</span><span class="n">paths</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">paths</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">greater</span><span class="o">&lt;&gt;</span><span class="p">());</span> <span class="c1">// case 1. only root</span> <span class="n">R</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">R</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">to_root</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="n">paths</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="k">return</span><span class="p">;</span> <span class="c1">// case 2. root and some leaves</span> <span class="n">ll</span> <span class="n">cost2</span> <span class="o">=</span> <span class="n">to_root</span> <span class="o">+</span> <span class="n">paths</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">first</span><span class="p">;</span> <span class="n">R</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">R</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">cost2</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">paths</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">R</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="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">R</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">cost2</span> <span class="o">+=</span> <span class="n">paths</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="c1">// case 3. only leaves</span> <span class="kt">int</span> <span class="n">idx</span> <span class="o">=</span> <span class="n">find_if</span><span class="p">(</span><span class="n">paths</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">paths</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="p">[</span><span class="o">&amp;</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">paths</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">second</span> <span class="o">!=</span> <span class="n">v</span><span class="p">.</span><span class="n">second</span><span class="p">;</span> <span class="p">})</span> <span class="o">-</span> <span class="n">paths</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> <span class="k">if</span><span class="p">(</span><span class="n">idx</span> <span class="o">!=</span> <span class="n">paths</span><span class="p">.</span><span class="n">size</span><span class="p">()){</span> <span class="n">ll</span> <span class="n">cost3</span> <span class="o">=</span> <span class="n">to_root</span> <span class="o">+</span> <span class="n">paths</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">first</span> <span class="o">+</span> <span class="n">paths</span><span class="p">[</span><span class="n">idx</span><span class="p">].</span><span class="n">first</span><span class="p">;</span> <span class="n">paths</span><span class="p">.</span><span class="n">erase</span><span class="p">(</span><span class="n">paths</span><span class="p">.</span><span class="n">begin</span><span class="p">()</span> <span class="o">+</span> <span class="n">idx</span><span class="p">);</span> <span class="n">R</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">R</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">cost3</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">paths</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">R</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="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">R</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">cost3</span> <span class="o">+=</span> <span class="n">paths</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="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">G</span><span class="p">[</span><span class="n">root</span><span class="p">])</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">U</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="n">Go</span><span class="p">(</span><span class="n">i</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="kt">int</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="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">a</span> <span class="o">&gt;&gt;</span> <span class="n">b</span> <span class="o">&gt;&gt;</span> <span class="n">c</span> <span class="o">&gt;&gt;</span> <span class="n">d</span><span class="p">;</span> <span class="n">Sum</span> <span class="o">+=</span> <span class="n">c</span> <span class="o">+</span> <span class="n">d</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">emplace_back</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">G</span><span class="p">[</span><span class="n">b</span><span class="p">].</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">d</span><span class="p">);</span> <span class="p">}</span> <span class="n">TreeDP</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="n">Go</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">2</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="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">R</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="o">-</span><span class="mi">1</span><span class="p">]);</span> <span class="n">cin</span> <span class="o">&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">t</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">Q</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">t</span><span class="p">,</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">Sum</span> <span class="o">-</span> <span class="n">R</span><span class="p">[</span><span class="n">t</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="p">}</span> </code></pre></div></div>JusticeHui문제 링크 http://icpc.me/17674백준25412 Measures2023-02-26T00:00:01+00:002023-02-26T00:00:01+00:00https://justicehui.github.io/ceoi/2023/02/26/BOJ25412<h3 id="문제-링크">문제 링크</h3> <ul> <li>http://icpc.me/25412</li> </ul> <h3 id="문제-출처">문제 출처</h3> <ul> <li>2022 CEOI Day2 2번</li> </ul> <h3 id="사용-알고리즘">사용 알고리즘</h3> <ul> <li>세그먼트 트리</li> </ul> <h3 id="시간복잡도">시간복잡도</h3> <ul> <li>$O((N+M) \log (N+M))$</li> </ul> <h3 id="풀이">풀이</h3> <h4 id="subtask-1-n-leq-2000-m-leq-10-10점">Subtask 1. $N \leq 2\,000, M \leq 10$ (10점)</h4> <p>모든 점들을 정렬합시다. $i$번째 사람과 $j(&gt; i)$번째 사람은 최소한 $(j-i)D$ 이상 떨어져 있어야 합니다. 따라서 두 사람은 최대 $((j-i)D-(P_j-P_i))/2$ 만큼 이동해야 합니다. 그러므로 $((j-i)D-(P_j-P_i))/2$의 최댓값은 정답의 상한입니다.</p> <p>$t$초 이후에는 두 사람의 거리가 최대 $2t$ 만큼 변할 수 있습니다. 따라서 정답 $T$는 모든 $i &lt; j$에 대해 $P_j-P_i+2T \geq (j-i)D$를 만족해야 합니다. 식을 정리하면 $T \geq ((j-i)D-(P_j-P_i))/2$가 되므로 정답의 하한도 구했습니다.</p> <p>상한과 하한이 같으므로 단순히 $((j-i)D-(P_j-P_i))/2$의 최댓값을 $O(M(N+M)^2)$ 시간에 구해서 출력하면 됩니다.</p> <h4 id="subtask-2-n-leq-200000-m-leq-10-24점">Subtask 2. $N \leq 200\,000, M \leq 10$ (24점)</h4> <p>함수 $f(i, j) = (j-i)D-(P_j-P_i)$를 정의합시다. $O(N^2)$개의 쌍을 모두 보지 않고 $f$의 최댓값을 구해야 합니다.<br /> 식을 정리하면 $f(i, j) = (jD-P_j) + (P_i-iD)$를 얻을 수 있고, 이때 $i$를 고정하면 $f(i, \ast)$의 최댓값은 suffix maximum을 이용해 구할 수 있습니다. 따라서 $O(N \log N + NM)$에 해결할 수 있습니다.</p> <p>아래 코드는 매번 <code class="language-plaintext highlighter-rouge">std::sort</code>를 호출하기 때문에 $O(NM \log N)$이지만, 새로 들어온 사람만 적절한 위치에 삽입하면 $O(N \log N + NM)$이 됩니다.</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">M</span><span class="p">,</span> <span class="n">D</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">ll</span><span class="o">&gt;</span> <span class="n">V</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="o">&gt;&gt;</span> <span class="n">M</span> <span class="o">&gt;&gt;</span> <span class="n">D</span><span class="p">;</span> <span class="n">V</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="k">auto</span> <span class="o">&amp;</span><span class="n">i</span> <span class="o">:</span> <span class="n">V</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</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">1</span><span class="p">;</span> <span class="n">iter</span><span class="o">&lt;=</span><span class="n">M</span><span class="p">;</span> <span class="n">iter</span><span class="o">++</span><span class="p">){</span> <span class="kt">int</span> <span class="n">t</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">t</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">t</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">res</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">sz</span> <span class="o">=</span> <span class="n">V</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="n">ll</span><span class="o">&gt;</span> <span class="n">mx</span><span class="p">(</span><span class="n">sz</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">mx</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="o">*</span> <span class="n">D</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="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">2</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">mx</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">mx</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">mx</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="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">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">mx</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">i</span><span class="p">]</span> <span class="o">-</span> <span class="n">i</span> <span class="o">*</span> <span class="n">D</span><span class="p">);</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">res</span><span class="o">/</span><span class="mi">2</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">res</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">?</span> <span class="s">".5"</span> <span class="o">:</span> <span class="s">""</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="n">iter</span><span class="o">==</span><span class="n">M</span><span class="p">];</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <h4 id="subtask-3-n--0-m-leq-200000-b_i-leq-b_i1-59점">Subtask 3. $N = 0, M \leq 200\,000, b_i \leq b_{i+1}$ (59점)</h4> <p>맨 뒤에 새로운 값이 추가되기 때문에 suffix maximum을 전처리할 수 없습니다. 하지만 $j$를 고정한 다음 $f(\ast, j)$의 최댓값을 구하는 방식으로 접근하면 $P_i-iD$의 prefix maximum을 구하는 것이므로 동일한 방법으로 해결할 수 있습니다.<br /> 원소를 중간에 삽입하거나 정렬할 필요가 없기 때문에 시간 복잡도는 $O(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="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">M</span><span class="p">,</span> <span class="n">D</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">ll</span><span class="o">&gt;</span> <span class="n">V</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="o">&gt;&gt;</span> <span class="n">M</span> <span class="o">&gt;&gt;</span> <span class="n">D</span><span class="p">;</span> <span class="n">V</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="k">auto</span> <span class="o">&amp;</span><span class="n">i</span> <span class="o">:</span> <span class="n">V</span><span class="p">)</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">i</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="n">vector</span><span class="o">&lt;</span><span class="n">ll</span><span class="o">&gt;</span> <span class="n">prefix</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">1</span><span class="p">;</span> <span class="n">iter</span><span class="o">&lt;=</span><span class="n">M</span><span class="p">;</span> <span class="n">iter</span><span class="o">++</span><span class="p">){</span> <span class="kt">int</span> <span class="n">t</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">t</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">M</span> <span class="o">&lt;=</span> <span class="mi">10</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">t</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">sz</span> <span class="o">=</span> <span class="n">V</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="mi">0</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">ll</span><span class="o">&gt;</span> <span class="n">mx</span><span class="p">(</span><span class="n">sz</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">mx</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="o">*</span> <span class="n">D</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="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">2</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">mx</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">mx</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">mx</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="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">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">mx</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">i</span><span class="p">]</span> <span class="o">-</span> <span class="n">i</span> <span class="o">*</span> <span class="n">D</span><span class="p">);</span> <span class="p">}</span> <span class="k">else</span><span class="p">{</span> <span class="n">prefix</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">t</span> <span class="o">-</span> <span class="n">iter</span><span class="o">*</span><span class="n">D</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="n">prefix</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">)</span> <span class="n">prefix</span><span class="p">.</span><span class="n">back</span><span class="p">()</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">prefix</span><span class="p">.</span><span class="n">back</span><span class="p">(),</span> <span class="n">prefix</span><span class="p">[</span><span class="n">prefix</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="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">iter</span><span class="o">*</span><span class="n">D</span> <span class="o">-</span> <span class="n">t</span> <span class="o">+</span> <span class="n">prefix</span><span class="p">.</span><span class="n">back</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">/</span><span class="mi">2</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">res</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">?</span> <span class="s">".5"</span> <span class="o">:</span> <span class="s">""</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="n">iter</span><span class="o">==</span><span class="n">M</span><span class="p">];</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <h4 id="subtask-4-n--0-m-leq-200000-100점">Subtask 4. $N = 0, M \leq 200\,000$ (100점)</h4> <p>새로운 수가 추가되었을 때 함수 $f(i, j) = (j-i)D-(P_j-P_i)$가 어떻게 변화하는지 살펴봅시다.<br /> $f(i, j) = (jD-P_j)+(P_i-iD) = (jD-P_j)-(iD-P_i)$의 최댓값을 구하는 것이 목표입니다. 어떤 위치 $x$에 수를 삽입하면 $x$보다 오른쪽에 있는 원소들의 $iD-P_i$ 값이 $D$씩 증가합니다.<br /> 기존에 있던 원소들 간의 $f$ 값은 이미 계산되어 있으므로, 새로 $x$에 삽입한 원소들에 의해 바뀐 $f$값, 즉 ($x$의 오른쪽에서의 최댓값) - ($x$의 왼쪽에서의 최솟값)을 구해서 정답에 반영해야 합니다.</p> <p>$x$보다 오른쪽에 있는 원소들의 값을 $D$씩 증가시키는 연산, 구간의 최댓값과 최솟값을 찾는 연산은 좌표 압축을 수행한 뒤 세그먼트 트리를 이용해 처리할 수 있습니다.</p> <p>전체 시간 복잡도는 $O((N+M) \log (N+M))$입니다.</p> <h3 id="전체-코드">전체 코드</h3> <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">using</span> <span class="n">PLL</span> <span class="o">=</span> <span class="n">pair</span><span class="o">&lt;</span><span class="n">ll</span><span class="p">,</span> <span class="n">ll</span><span class="o">&gt;</span><span class="p">;</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="n">PLL</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">ll</span> <span class="n">L</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="k">const</span> <span class="n">PLL</span> <span class="nf">O</span><span class="p">(</span><span class="mh">0x3f3f3f3f3f3f3f3f</span><span class="p">,</span> <span class="mh">0xc0c0c0c0c0c0c0c0</span><span class="p">);</span> <span class="n">PLL</span> <span class="nf">Merge</span><span class="p">(</span><span class="k">const</span> <span class="n">PLL</span> <span class="o">&amp;</span><span class="n">a</span><span class="p">,</span> <span class="k">const</span> <span class="n">PLL</span> <span class="o">&amp;</span><span class="n">b</span><span class="p">){</span> <span class="k">return</span> <span class="n">make_pair</span><span class="p">(</span><span class="n">min</span><span class="p">(</span><span class="n">a</span><span class="p">.</span><span class="n">first</span><span class="p">,</span><span class="n">b</span><span class="p">.</span><span class="n">first</span><span class="p">),</span> <span class="n">max</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="n">b</span><span class="p">.</span><span class="n">second</span><span class="p">));</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">Push</span><span class="p">(</span><span class="kt">int</span> <span class="n">node</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">T</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">first</span> <span class="o">+=</span> <span class="n">L</span><span class="p">[</span><span class="n">node</span><span class="p">];</span> <span class="n">T</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">second</span> <span class="o">+=</span> <span class="n">L</span><span class="p">[</span><span class="n">node</span><span class="p">];</span> <span class="k">if</span><span class="p">(</span><span class="n">s</span> <span class="o">!=</span> <span class="n">e</span><span class="p">)</span> <span class="n">L</span><span class="p">[</span><span class="n">node</span><span class="o">&lt;&lt;</span><span class="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="n">L</span><span class="p">[</span><span class="n">node</span><span class="p">],</span> <span class="n">L</span><span class="p">[</span><span class="n">node</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="o">+=</span> <span class="n">L</span><span class="p">[</span><span class="n">node</span><span class="p">];</span> <span class="n">L</span><span class="p">[</span><span class="n">node</span><span class="p">]</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">Update</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">ll</span> <span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">node</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="kt">int</span> <span class="n">s</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="kt">int</span> <span class="n">e</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">Push</span><span class="p">(</span><span class="n">node</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="k">if</span><span class="p">(</span><span class="n">r</span> <span class="o">&lt;</span> <span class="n">s</span> <span class="o">||</span> <span class="n">e</span> <span class="o">&lt;</span> <span class="n">l</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">l</span> <span class="o">&lt;=</span> <span class="n">s</span> <span class="o">&amp;&amp;</span> <span class="n">e</span> <span class="o">&lt;=</span> <span class="n">r</span><span class="p">){</span> <span class="n">L</span><span class="p">[</span><span class="n">node</span><span class="p">]</span> <span class="o">+=</span> <span class="n">v</span><span class="p">;</span> <span class="n">Push</span><span class="p">(</span><span class="n">node</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="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="n">m</span> <span class="o">=</span> <span class="p">(</span><span class="n">s</span> <span class="o">+</span> <span class="n">e</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span> <span class="n">Update</span><span class="p">(</span><span class="n">l</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">node</span><span class="o">&lt;&lt;</span><span class="mi">1</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">m</span><span class="p">);</span> <span class="n">Update</span><span class="p">(</span><span class="n">l</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">node</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="n">m</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">e</span><span class="p">);</span> <span class="n">T</span><span class="p">[</span><span class="n">node</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">node</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">node</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">void</span> <span class="nf">Set</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="n">ll</span> <span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">node</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="kt">int</span> <span class="n">s</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="kt">int</span> <span class="n">e</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">Push</span><span class="p">(</span><span class="n">node</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="k">if</span><span class="p">(</span><span class="n">s</span> <span class="o">==</span> <span class="n">e</span><span class="p">){</span> <span class="n">T</span><span class="p">[</span><span class="n">node</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="n">v</span><span class="p">,</span> <span class="n">v</span><span class="p">};</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="n">m</span> <span class="o">=</span> <span class="p">(</span><span class="n">s</span> <span class="o">+</span> <span class="n">e</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">x</span> <span class="o">&lt;=</span> <span class="n">m</span><span class="p">)</span> <span class="n">Set</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="n">node</span><span class="o">&lt;&lt;</span><span class="mi">1</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">m</span><span class="p">),</span> <span class="n">Push</span><span class="p">(</span><span class="n">node</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="n">m</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">e</span><span class="p">);</span> <span class="k">else</span> <span class="n">Set</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="n">node</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="n">m</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">e</span><span class="p">),</span> <span class="n">Push</span><span class="p">(</span><span class="n">node</span><span class="o">&lt;&lt;</span><span class="mi">1</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">m</span><span class="p">);</span> <span class="n">T</span><span class="p">[</span><span class="n">node</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">node</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">node</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="n">PLL</span> <span class="nf">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="kt">int</span> <span class="n">node</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="kt">int</span> <span class="n">s</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="kt">int</span> <span class="n">e</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">Push</span><span class="p">(</span><span class="n">node</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="k">if</span><span class="p">(</span><span class="n">r</span> <span class="o">&lt;</span> <span class="n">s</span> <span class="o">||</span> <span class="n">e</span> <span class="o">&lt;</span> <span class="n">l</span><span class="p">)</span> <span class="k">return</span> <span class="n">O</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">l</span> <span class="o">&lt;=</span> <span class="n">s</span> <span class="o">&amp;&amp;</span> <span class="n">e</span> <span class="o">&lt;=</span> <span class="n">r</span><span class="p">)</span> <span class="k">return</span> <span class="n">T</span><span class="p">[</span><span class="n">node</span><span class="p">];</span> <span class="kt">int</span> <span class="n">m</span> <span class="o">=</span> <span class="p">(</span><span class="n">s</span> <span class="o">+</span> <span class="n">e</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span> <span class="k">return</span> <span class="n">Merge</span><span class="p">(</span><span class="n">Query</span><span class="p">(</span><span class="n">l</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">node</span><span class="o">&lt;&lt;</span><span class="mi">1</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">m</span><span class="p">),</span> <span class="n">Query</span><span class="p">(</span><span class="n">l</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">node</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="n">m</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">e</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">M</span><span class="p">,</span> <span class="n">D</span><span class="p">,</span> <span class="n">P</span><span class="p">[</span><span class="mi">202020</span><span class="p">],</span> <span class="n">F</span><span class="p">[</span><span class="mi">202020</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="n">ll</span><span class="p">,</span><span class="n">ll</span><span class="o">&gt;&gt;</span> <span class="n">C</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">202020</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">F</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">F</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">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="o">&gt;&gt;</span> <span class="n">M</span> <span class="o">&gt;&gt;</span> <span class="n">D</span><span class="p">;</span> <span class="n">C</span><span class="p">.</span><span class="n">reserve</span><span class="p">(</span><span class="n">N</span><span class="o">+</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">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="o">+</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="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="n">C</span><span class="p">.</span><span class="n">emplace_back</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="n">i</span><span class="p">);</span> <span class="n">sort</span><span class="p">(</span><span class="n">C</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">C</span><span class="p">.</span><span class="n">end</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="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">O</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">q</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">q</span><span class="o">&lt;=</span><span class="n">N</span><span class="o">+</span><span class="n">M</span><span class="p">;</span> <span class="n">q</span><span class="o">++</span><span class="p">){</span> <span class="kt">int</span> <span class="n">pos</span> <span class="o">=</span> <span class="n">lower_bound</span><span class="p">(</span><span class="n">C</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">C</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">P</span><span class="p">[</span><span class="n">q</span><span class="p">],</span> <span class="p">(</span><span class="n">ll</span><span class="p">)</span><span class="n">q</span><span class="p">))</span> <span class="o">-</span> <span class="n">C</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> <span class="kt">int</span> <span class="n">idx</span> <span class="o">=</span> <span class="n">Get</span><span class="p">(</span><span class="n">pos</span><span class="p">);</span> <span class="n">Add</span><span class="p">(</span><span class="n">pos</span><span class="p">);</span> <span class="n">Set</span><span class="p">(</span><span class="n">pos</span><span class="p">,</span> <span class="n">idx</span> <span class="o">*</span> <span class="n">D</span> <span class="o">-</span> <span class="n">P</span><span class="p">[</span><span class="n">q</span><span class="p">]);</span> <span class="n">Update</span><span class="p">(</span><span class="n">pos</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">C</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">D</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">Query</span><span class="p">(</span><span class="n">pos</span><span class="p">,</span> <span class="n">C</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">second</span> <span class="o">-</span> <span class="n">Query</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">pos</span><span class="p">).</span><span class="n">first</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="n">q</span> <span class="o">&gt;</span> <span class="n">N</span><span class="p">)</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">res</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">res</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">?</span> <span class="s">".5"</span> <span class="o">:</span> <span class="s">""</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="n">q</span><span class="o">==</span><span class="n">N</span><span class="o">+</span><span class="n">M</span><span class="p">];</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div>JusticeHui문제 링크 http://icpc.me/25412백준19614 Travelling Salesperson2023-02-26T00:00:00+00:002023-02-26T00:00:00+00:00https://justicehui.github.io/cco/2023/02/26/BOJ19614<h3 id="문제-링크">문제 링크</h3> <ul> <li>http://icpc.me/19614</li> </ul> <h3 id="문제-출처">문제 출처</h3> <ul> <li>2020 CCO Day2 1번</li> </ul> <h3 id="사용-알고리즘">사용 알고리즘</h3> <ul> <li>연결 리스트</li> </ul> <h3 id="시간복잡도">시간복잡도</h3> <ul> <li>$O(N^2)$</li> </ul> <h3 id="풀이">풀이</h3> <p>정점을 하나씩 추가해서 경로를 만드는 방식으로 진행합니다.</p> <p>지금까지 만든 경로를 $(v_1, v_2, \cdots, v_k)$, <code class="language-plaintext highlighter-rouge">RR...RBB...B</code> 형태라고 합시다.<br /> 새로운 정점 $x$를 추가할 때 만약 $(x, v_1)$ 간선이 <code class="language-plaintext highlighter-rouge">R</code>이면 앞에 추가하고 $(v_k, x)$ 간선이 <code class="language-plaintext highlighter-rouge">B</code>이면 뒤에 추가하면 됩니다. 두 가지 경우에 모두 해당하지 않는다면 $(x, v_1)$이 <code class="language-plaintext highlighter-rouge">B</code>, $(v_k, x)$가 <code class="language-plaintext highlighter-rouge">R</code>인 상태입니다.<br /> 만약 $(v_1,v_k)$가 <code class="language-plaintext highlighter-rouge">R</code>이면 $v_k$를 $v_1$ 앞에 붙인 다음, $(x,v_k)$가 <code class="language-plaintext highlighter-rouge">R</code>이니까 $x$를 앞에 붙이면 됩니다. 그렇지 않다면 $(v1,v_k)$가 <code class="language-plaintext highlighter-rouge">B</code>일 텐데, 이때는 $v_k$ 뒤에 $v_1$을 붙인 다음 $x$를 뒤에 붙이면 됩니다.</p> <p>남은 부분은 원하는 정점을 시작 정점으로 만드는 것입니다. 시작 정점을 가장 마지막에 추가한 다음, 만약 시작 정점이 맨 뒤로 갔다면 경로를 뒤집어서 시작 정점이 되도록 보장할 수 있습니다.</p> <p>연결 리스트를 사용하면 시작점마다 $O(N)$ 시간이 걸려서 총 $O(N^2)$ 시간에 문제를 해결할 수 있습니다.</p> <h3 id="전체-코드">전체 코드</h3> <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">2020</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="kt">int</span> <span class="n">src</span><span class="p">){</span> <span class="n">list</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="n">function</span><span class="o">&lt;</span><span class="kt">void</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">add</span> <span class="o">=</span> <span class="p">[</span><span class="o">&amp;</span><span class="n">res</span><span class="p">](</span><span class="kt">int</span> <span class="n">v</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&lt;=</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">v</span><span class="p">);</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="o">*</span><span class="n">res</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">b</span> <span class="o">=</span> <span class="o">*</span><span class="n">res</span><span class="p">.</span><span class="n">rbegin</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">v</span><span class="p">][</span><span class="n">a</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="n">res</span><span class="p">.</span><span class="n">push_front</span><span class="p">(</span><span class="n">v</span><span class="p">);</span> <span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">v</span><span class="p">][</span><span class="n">b</span><span class="p">]</span> <span class="o">==</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">v</span><span class="p">);</span> <span class="k">else</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">b</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="n">res</span><span class="p">.</span><span class="n">pop_back</span><span class="p">(),</span> <span class="n">res</span><span class="p">.</span><span class="n">push_front</span><span class="p">(</span><span class="n">b</span><span class="p">),</span> <span class="n">res</span><span class="p">.</span><span class="n">push_front</span><span class="p">(</span><span class="n">v</span><span class="p">);</span> <span class="k">else</span> <span class="n">res</span><span class="p">.</span><span class="n">pop_front</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">a</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">v</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="k">if</span><span class="p">(</span><span class="n">i</span> <span class="o">!=</span> <span class="n">src</span><span class="p">)</span> <span class="n">add</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> <span class="n">add</span><span class="p">(</span><span class="n">src</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="o">*</span><span class="n">res</span><span class="p">.</span><span class="n">begin</span><span class="p">()</span> <span class="o">!=</span> <span class="n">src</span><span class="p">)</span> <span class="n">res</span><span class="p">.</span><span class="n">reverse</span><span class="p">();</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">N</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">for</span><span class="p">(</span><span class="k">auto</span> <span class="n">i</span> <span class="o">:</span> <span class="n">res</span><span class="p">)</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">i</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="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="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">2</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">1</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</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="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">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">A</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">c</span> <span class="o">==</span> <span class="sc">'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">Solve</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> <span class="p">}</span> </code></pre></div></div>JusticeHui문제 링크 http://icpc.me/19614백준21815 Through Another Maze Darkly2023-02-25T00:00:02+00:002023-02-25T00:00:02+00:00https://justicehui.github.io/cco/2023/02/25/BOJ21825<h3 id="문제-링크">문제 링크</h3> <ul> <li>http://icpc.me/21825</li> </ul> <h3 id="문제-출처">문제 출처</h3> <ul> <li>2021 CCO Day1 3번</li> </ul> <h3 id="사용-알고리즘">사용 알고리즘</h3> <ul> <li>DFS</li> </ul> <h3 id="시간복잡도">시간복잡도</h3> <ul> <li>$$</li> </ul> <h3 id="풀이">풀이</h3> <p>다음과 같은 트리를 생각해 봅시다. 각 정점에서 가장 먼저 사용하는 간선을 화살표로 표현했습니다.</p> <p><img src="https://i.imgur.com/8D7Lqm3.png" alt="" /></p> <p>첫 번째 순회에서는 <code class="language-plaintext highlighter-rouge">1 2 5 2 6 8 6 2 1 3 1</code> 순서대로 방문합니다. 첫 번째 순회를 한 이후의 트리는 다음과 같습니다. 첫 번째 순회에서 방문한 정점들의 화살표가 모두 첫 번째 자식(없다면 부모) 정점을 가리키고 있다는 점을 관찰할 수 있습니다.</p> <p><img src="https://i.imgur.com/E6i48dh.png" alt="" /></p> <p>두 번째 순회에서는 <code class="language-plaintext highlighter-rouge">1 2 4 2 5 2 6 8 6 2 1 3 7 3 1</code> 순서대로 방문합니다. $t-1$번째 순회에서 방문한 정점은 항상 $t$번째 순회에서 방문한다는 점도 알 수 있습니다. 또한, 각 순회에서 정점을 방문하는 순서가 역전되지 않습니다.<br /> 따라서 자식 정점들을 적당한 순서대로 배치한 다음 오일러 투어를 구해 놓으면, 두 정수 $t, k$가 주어졌을 때 $t$번째 순회에서 $k$번째로 방문하는 정점을 세그먼트 트리 등을 이용해 오프라인으로 구할 수 있습니다.</p> <p>입력으로 트리의 인접 리스트가 주어지면 부모 정점의 위치 $p$를 구합시다. $p$ 이전에 있는 정점은 현재 정점을 처음으로 방문한 순회에서, $p$ 이후에 있는 정점은 그 다음 순회에서 방문하게 됩니다. 따라서 DFS를 이용해 $O(N)$ 시간에 각 정점을 처음으로 방문하는 시점을 구할 수 있습니다. 각 간선을 처음 사용하게 되는 시점도 함께 구할 수 있습니다.<br /> 이후 구현의 편의를 위해 부모 정점이 가장 마지막에 오도록 인접 리스트를 cyclic shift 합시다.</p> <p>이제 $K$번째로 방문하는 정점을 구하는 쿼리를 처리할 차례입니다. 우리의 궁극적인 목표는 $K$를 적당한 정수 $t, k$로 바꿔서, $t$번째 순회에서 $k$번째로 방문하는 정점을 구하는 문제로 변환하는 것입니다.<br /> 각 간선이 처음 사용되는 시점을 알고 있다면, 누적 합과 비슷한 방식으로 각 순회의 길이를 상수 시간에 구할 수 있습니다. 따라서 순회의 길이의 누적합 위에서 이분 탐색을 하면 $O(\log N)$ 시간에 $t$를 구할 수 있습니다. $N+1$번째 순회부터는 항상 모든 정점과 간선을 방문한다는 것에 유의하세요.<br /> $t$를 구했다면 $k$를 구하는 것은 간단합니다. 단순히 모듈러 연산을 이용하면 되기 때문입니다.</p> <p>$t, k$가 주어졌을 때 실제 정답을 찾는 것은 쿼리를 $t$ 오름차순으로 정렬한 다음, 세그먼트 트리에서 $k$번째 원소를 찾는 연산을 사용하면 됩니다. 자세한 구현은 코드의 64번째 줄부터 참고하시면 됩니다.</p> <h3 id="전체-코드">전체 코드</h3> <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="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">21</span><span class="p">;</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">Q</span><span class="p">,</span> <span class="n">On</span><span class="p">[</span><span class="mi">808080</span><span class="p">],</span> <span class="n">R</span><span class="p">[</span><span class="mi">808080</span><span class="p">],</span> <span class="n">T</span><span class="p">[</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">G</span><span class="p">[</span><span class="mi">808080</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">Tour</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">Idx</span><span class="p">[</span><span class="mi">808080</span><span class="p">];</span> <span class="c1">// Idx[t] : t에 켜지는 정점</span> <span class="n">ll</span> <span class="n">TourSize</span><span class="p">[</span><span class="mi">808080</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="kt">int</span> <span class="n">v</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="n">SZ</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="n">v</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">int</span> <span class="nf">Kth</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">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">Tour</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="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="kt">int</span> <span class="n">m</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="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">Get</span><span class="p">(</span><span class="n">m</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="n">x</span><span class="p">)</span> <span class="n">r</span> <span class="o">=</span> <span class="n">m</span><span class="p">;</span> <span class="k">else</span> <span class="n">l</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="p">}</span> <span class="k">return</span> <span class="n">r</span><span class="p">;</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">GetTime</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">b</span><span class="o">=-</span><span class="mi">1</span><span class="p">,</span> <span class="kt">int</span> <span class="n">t</span><span class="o">=</span><span class="mi">1</span><span class="p">){</span> <span class="n">On</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">t</span><span class="p">;</span> <span class="kt">int</span> <span class="n">pos</span> <span class="o">=</span> <span class="n">find</span><span class="p">(</span><span class="n">G</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">G</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">b</span><span class="p">)</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">begin</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">pos</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">GetTime</span><span class="p">(</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="n">v</span><span class="p">,</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="n">pos</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">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">GetTime</span><span class="p">(</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="n">v</span><span class="p">,</span> <span class="n">t</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">b</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">rotate</span><span class="p">(</span><span class="n">G</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">G</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="o">+</span><span class="n">pos</span><span class="p">,</span> <span class="n">G</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="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">Idx</span><span class="p">[</span><span class="n">max</span><span class="p">(</span><span class="n">On</span><span class="p">[</span><span class="n">s</span><span class="p">],</span> <span class="n">On</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">Tour</span><span class="p">.</span><span class="n">size</span><span class="p">());</span> <span class="n">Tour</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="p">}</span> <span class="kt">void</span> <span class="nf">GetTour</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">b</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="n">i</span> <span class="o">!=</span> <span class="n">b</span><span class="p">)</span> <span class="n">AddEdge</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">GetTour</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">AddEdge</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="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="o">&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">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">sz</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">sz</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">resize</span><span class="p">(</span><span class="n">sz</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">G</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">j</span><span class="p">;</span> <span class="n">rotate</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">begin</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">begin</span><span class="p">()</span><span class="o">+</span><span class="mi">1</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">end</span><span class="p">());</span> <span class="p">}</span> <span class="n">GetTime</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="n">GetTour</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">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">TourSize</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">TourSize</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">Idx</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="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">TourSize</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+=</span> <span class="n">TourSize</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">vector</span><span class="o">&lt;</span><span class="n">tuple</span><span class="o">&lt;</span><span class="n">ll</span><span class="p">,</span><span class="n">ll</span><span class="p">,</span><span class="n">ll</span><span class="o">&gt;&gt;</span> <span class="n">V</span><span class="p">;</span> <span class="c1">// iteration, kth, idx</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">q</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">q</span><span class="o">&lt;=</span><span class="n">Q</span><span class="p">;</span> <span class="n">q</span><span class="o">++</span><span class="p">){</span> <span class="n">ll</span> <span class="n">K</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">K</span><span class="p">;</span> <span class="kt">int</span> <span class="n">it</span> <span class="o">=</span> <span class="n">lower_bound</span><span class="p">(</span><span class="n">TourSize</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">TourSize</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">K</span><span class="p">)</span> <span class="o">-</span> <span class="n">TourSize</span><span class="p">;</span> <span class="n">K</span> <span class="o">-=</span> <span class="n">TourSize</span><span class="p">[</span><span class="n">it</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">it</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">K</span> <span class="o">=</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="n">Tour</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">V</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">it</span><span class="p">,</span> <span class="n">K</span><span class="p">,</span> <span class="n">q</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="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">it</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">it</span><span class="o">&lt;=</span><span class="n">N</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span> <span class="n">it</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">e</span> <span class="o">:</span> <span class="n">Idx</span><span class="p">[</span><span class="n">it</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="mi">1</span><span class="p">);</span> <span class="k">while</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="o">&amp;&amp;</span> <span class="n">get</span><span class="o">&lt;</span><span class="mi">0</span><span class="o">&gt;</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="o">==</span> <span class="n">it</span><span class="p">){</span> <span class="n">R</span><span class="p">[</span><span class="n">get</span><span class="o">&lt;</span><span class="mi">2</span><span class="o">&gt;</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="o">=</span> <span class="n">Kth</span><span class="p">(</span><span class="n">get</span><span class="o">&lt;</span><span class="mi">1</span><span class="o">&gt;</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">i</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">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">Q</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">Tour</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">second</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div>JusticeHui문제 링크 http://icpc.me/21825백준21824 Weird Numeral System2023-02-25T00:00:01+00:002023-02-25T00:00:01+00:00https://justicehui.github.io/cco/2023/02/25/BOJ21824<h3 id="문제-링크">문제 링크</h3> <ul> <li>http://icpc.me/21824</li> </ul> <h3 id="문제-출처">문제 출처</h3> <ul> <li>2021 CCO Day1 2번</li> </ul> <h3 id="사용-알고리즘">사용 알고리즘</h3> <ul> <li>DFS/BFS</li> </ul> <h3 id="풀이">풀이</h3> <p>진법의 개념에서 크게 벗어나지 않기 위해서 일단 $M \leq K, n \neq 0$인 상황만 생각해 봅시다.<br /> 이런 상황에서는 매 단계마다 $n$이 존재할 수 있는 구간을 $[-K^t, K^t]$에서 $[-K^{t-1}, K^{t-1}]$으로 축소시킬 수 있습니다. $n \equiv a_i \pmod K$인 $a_i$를 마지막에 붙인다고 가정한 다음, $(n-a_i)/K$에 대해서 문제를 해결하면 되기 때문입니다. 따라서 $M \leq K$이면 재귀적으로 문제를 해결할 수 있습니다.</p> <p>$n = 0$일 때 공집합을 출력하면 안 된다는 이상한 조건이 붙어있습니다. 공집합이 아니라는 것은 마지막에 어떤 원소 $a_i$를 붙여야 한다는 것이고, 당연히 $a_i \equiv 0 \pmod K$를 만족해야 합니다.<br /> 마지막에 $a_i$를 붙여서 $0$이 되기 위해서는 $(-a_i/K)\times K + a_i$ 꼴이 되어야 합니다. 따라서 위에서 설명한 풀이를 이용해 $-a_i/K$를 만드는 방법을 구하면 됩니다.</p> <p>마지막으로 $M &gt; K$인 경우를 생각해 봅시다. 이 경우에는 구간을 $K$배만큼 축소가 불가능할 수도 있기 때문에 위에서 설명한 풀이를 적용하지 못합니다.<br /> 어떤 상황에서 축소에 실패하는지 살펴봅시다. 대부분의 경우에는 $a_i$를 더하는 것보다 $K$로 나누는 것의 영향력이 더 크기 때문에 축소를 할 수 있습니다. 하지만 $\vert n \vert \leq M$이면 $a_i$를 더하는 것으로 인해서 $[-M, M]$ 범위 밖으로 벗어나는 일이 발생할 수 있습니다. 따라서 절댓값이 $M$ 이하인 수들에 대해서는 다른 방법으로 경로를 탐색해야 합니다.<br /> 다행히도 $M$이 $2\,500$ 정도로 굉장히 작기 때문에 단순히 BFS를 이용해 전처리해도 괜찮습니다. $n$을 계속 축소하다가 $\vert n \vert \leq M$이 되면 BFS로 전처리한 경로를 사용하면 됩니다.</p> <p>재귀적으로 탐색하는 깊이가 $O(\log_K N)$ 정도로 매우 작기 때문에 시간 제한 안에 문제를 해결할 수 있습니다.</p> <h3 id="전체-코드">전체 코드</h3> <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">K</span><span class="p">,</span> <span class="n">Q</span><span class="p">,</span> <span class="n">D</span><span class="p">,</span> <span class="n">M</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="mi">5050</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">1010101</span><span class="p">];</span> <span class="n">unordered_map</span><span class="o">&lt;</span><span class="n">ll</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">Vst</span><span class="p">,</span> <span class="n">Prv</span><span class="p">;</span> <span class="kr">inline</span> <span class="n">ll</span> <span class="nf">Mod</span><span class="p">(</span><span class="n">ll</span> <span class="n">t</span><span class="p">){</span> <span class="k">return</span> <span class="p">(</span><span class="n">t</span> <span class="o">%=</span> <span class="n">K</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">?</span> <span class="n">t</span> <span class="o">:</span> <span class="n">t</span> <span class="o">+</span> <span class="n">K</span><span class="p">;</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">SmallBFS</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">M</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="n">Vst</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">queue</span><span class="o">&lt;</span><span class="n">ll</span><span class="o">&gt;</span> <span class="n">Que</span><span class="p">;</span> <span class="n">Que</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="n">Vst</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">while</span><span class="p">(</span><span class="o">!</span><span class="n">Que</span><span class="p">.</span><span class="n">empty</span><span class="p">()){</span> <span class="n">ll</span> <span class="n">v</span> <span class="o">=</span> <span class="n">Que</span><span class="p">.</span><span class="n">front</span><span class="p">();</span> <span class="n">Que</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="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">D</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="n">ll</span> <span class="n">nxt</span> <span class="o">=</span> <span class="n">v</span> <span class="o">*</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="n">abs</span><span class="p">(</span><span class="n">nxt</span><span class="p">)</span> <span class="o">&gt;</span> <span class="n">M</span> <span class="o">||</span> <span class="n">Vst</span><span class="p">[</span><span class="n">nxt</span><span class="p">])</span> <span class="k">continue</span><span class="p">;</span> <span class="n">Que</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">nxt</span><span class="p">);</span> <span class="n">Vst</span><span class="p">[</span><span class="n">nxt</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">Prv</span><span class="p">[</span><span class="n">nxt</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="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">Check</span><span class="p">(</span><span class="n">ll</span> <span class="n">n</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="k">auto</span> <span class="n">it</span><span class="o">=</span><span class="n">Vst</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="n">n</span><span class="p">);</span> <span class="n">it</span> <span class="o">!=</span> <span class="n">Vst</span><span class="p">.</span><span class="n">end</span><span class="p">())</span> <span class="k">return</span> <span class="n">it</span><span class="o">-&gt;</span><span class="n">second</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">Mod</span><span class="p">(</span><span class="n">n</span><span class="p">)])</span> <span class="k">if</span><span class="p">(</span><span class="n">Check</span><span class="p">((</span><span class="n">n</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="o">/</span> <span class="n">K</span><span class="p">))</span> <span class="p">{</span> <span class="n">Prv</span><span class="p">[</span><span class="n">n</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">return</span> <span class="n">Vst</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="p">}</span> <span class="k">return</span> <span class="n">Vst</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="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">Path</span><span class="p">(</span><span class="n">ll</span> <span class="n">n</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">if</span><span class="p">(</span><span class="n">n</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">Check</span><span class="p">(</span><span class="n">n</span><span class="p">))</span> <span class="k">return</span> <span class="p">{};</span> <span class="k">while</span><span class="p">(</span><span class="n">n</span> <span class="o">!=</span> <span class="mi">0</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">Prv</span><span class="p">[</span><span class="n">n</span><span class="p">]),</span> <span class="n">n</span> <span class="o">=</span> <span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="n">Prv</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="n">reverse</span><span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">res</span><span class="p">.</span><span class="n">end</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">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">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">D</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="mi">0</span><span class="p">)</span> <span class="k">return</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="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="mi">0</span><span class="p">]){</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">Check</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="o">/</span> <span class="n">K</span><span class="p">))</span> <span class="k">continue</span><span class="p">;</span> <span class="n">res</span> <span class="o">=</span> <span class="n">Path</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="o">/</span> <span class="n">K</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">A</span><span class="p">[</span><span class="n">i</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">return</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">K</span> <span class="o">&gt;&gt;</span> <span class="n">Q</span> <span class="o">&gt;&gt;</span> <span class="n">D</span> <span class="o">&gt;&gt;</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">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">D</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">Mod</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">SmallBFS</span><span class="p">();</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">q</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">q</span><span class="o">&lt;=</span><span class="n">Q</span><span class="p">;</span> <span class="n">q</span><span class="o">++</span><span class="p">){</span> <span class="n">ll</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="k">auto</span> <span class="n">path</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">n</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="n">path</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">"IMPOSSIBLE</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="k">else</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">path</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">cout</span> <span class="o">&lt;&lt;</span> <span class="n">path</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="se">\n</span><span class="s">"</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="o">==</span><span class="n">path</span><span class="p">.</span><span class="n">size</span><span class="p">()];</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div>JusticeHui문제 링크 http://icpc.me/21824