Jekyll2021-07-26T19:41:07+00:00https://justicehui.github.io/rss/JusticeHui가 PS하는 블로그Let's solve problem with JusticeHui!JusticeHui2021 KOI 2차대회 고등부 문제 풀이2021-07-26T07:31:00+00:002021-07-26T07:31:00+00:00https://justicehui.github.io/koi/2021/07/26/koi-2021-2<h3 id="문제-감상">문제 감상</h3> <p>성인이라서 대회에 참가하지는 못하지만, <a href="/koi/2021/05/17/koi-2021-1/">2021 KOI 1차대회</a>처럼 문제 풀이는 꾸준히 작성하려고 합니다.</p> <p>2019년부터 1~2번 문제 난이도가 계속해서 상승하고 있습니다. 올해 고등부 1, 2번 모두 KOI가 4문제 체제로 자리잡은 2011년 이후에 출제된 고등부 1, 2번 문제 중 가장 어렵게 느껴졌습니다. 내년에는 어떻게 출제가 될지 궁금해지네요.</p> <p>한편, 고등부 3번은 KOI에 거의 출제되지 않던 문자열 문제가 출제되었습니다. Trie나 KMP와 같은 비교적 쉽고 많은 학생들이 알고 있는 알고리즘이 아닌 Suffix Array / Longest Common Prefix가 나왔다는 점에서 큰 이변이라고 생각합니다. 올해 고등부 3번 문제는 SA/LCP를 알고 있는 학생이라면 10초 만에 풀이를 떠올릴 수 있지만, SA/LCP를 잘 이해하고 있는 학생은 한 손으로 셀 수 있을 정도로 적기 때문에 순위에 큰 영향을 주지 않을 것 같습니다.</p> <p>고등부 4번은 2020 SciOI에 출제된 <a href="https://www.acmicpc.net/problem/18803">방역</a>이라는 문제와 비슷해 보이는데, 어려워서 아직 풀지 못했습니다.</p> <p>일단 1, 2, 3번 문제의 풀이를 작성했고, 4번 문제는 풀게 된다면 추가하도록 하겠습니다.<br />아직 문제를 채점할 수 있는 곳이 없어서 부득이하게 검증되지 않은 코드를 올려놓았습니다. 문제를 채점할 수 있는 곳이 생기면 코드를 검증한 뒤 다시 올리겠습니다.</p> <h3 id="1번">1번</h3> <p>크기가 $1, 2, \cdots , i$인 동심원을 만드는데 필요한 페인트의 양은 $i(i+1)/2$이기 때문에, 크기가 $\lfloor \sqrt{A+B} \rfloor$인 원까지만 고려해도 충분합니다. $A+B \leq 100\,000$이므로 $450$까지만 고려하면 됩니다.</p> <p>이 관찰을 이용하면 41점을 받을 수 있는 $O(AB \sqrt {A+B})$ 풀이는 쉽게 찾을 수 있습니다.<br />빨간색 페인트를 $a$, 파란색 페인트를 $b$만큼 사용해서 크기가 $1, 2, \cdots , i$인 동심원을 만드는 경우의 수를 $D(i,a,b)$라고 정의합시다. $D(i,a,b) = D(i-1,a-i,b)+D(i-1,a,b-i)$이므로 각 상태를 상수 시간에 계산할 수 있습니다.</p> <p>각 상태는 이미 상수 시간에 계산할 수 있기 때문에 더 최적화를 하는 것은 불가능하고, 상태의 개수를 줄이는 방법을 생각해보는 것이 좋습니다. 조금만 고민해보면 90점을 받을 수 있는 $O(TA\sqrt{A+B})$풀이도 쉽게 찾을 수 있습니다.<br />빨간색 물감을 $a$만큼 사용하고, <strong>파란색 물감은 $B$ 이하로 사용해서</strong> 크기가 $1,2,\cdots,i$인 동심원을 만드는 경우의 수를 $D(i,a)$라고 정의합시다. $i$번째 동심원까지 빨간색 물감을 $a$만큼 사용했다면 파란색 물감은 $i*(i+1)/2-a$만큼 사용한 것이기 때문에 $a$만 저장해도 충분합니다. 조건문이 몇 개 붙긴 하지만, 41점 풀이와 비슷하게 점화식을 계산할 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 1번 90점 풀이</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">int</span> <span class="o">&amp;</span><span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">){</span> <span class="n">a</span> <span class="o">+=</span> <span class="n">b</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">a</span> <span class="o">&gt;=</span> <span class="n">MOD</span><span class="p">)</span> <span class="n">a</span> <span class="o">-=</span> <span class="n">MOD</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">Score90</span><span class="p">(</span><span class="kt">int</span> <span class="n">A</span><span class="p">,</span> <span class="kt">int</span> <span class="n">B</span><span class="p">){</span> <span class="kt">int</span> <span class="n">ret</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="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">450</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">k</span> <span class="o">=</span> <span class="n">i</span> <span class="o">*</span> <span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;=</span><span class="n">A</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="mi">0</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">j</span> <span class="o">-</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="n">Add</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">],</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</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="k">if</span><span class="p">(</span><span class="n">k</span> <span class="o">-</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">B</span><span class="p">)</span> <span class="n">Add</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">],</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">]);</span> <span class="n">Add</span><span class="p">(</span><span class="n">ret</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="p">}</span> <span class="p">}</span> <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <p>이 풀이는 테스트 케이스마다 $B$가 계속 달라질 수 있기 때문에, 기존에 구한 DP 테이블을 다른 테스트 케이스에서 재활용하지 못합니다. 만약 DP 테이블을 재활용할 수 있는 방법을 찾는다면 시간 복잡도에서 $T$를 없앨 수 있습니다.</p> <p>$B$가 매번 다른 것이 문제이므로 $B$ 조건을 없앤 상태로 점화식을 세워봅시다. 빨간색 물감을 $a$만큼 사용하고, <strong>파란색 물감은 자유롭게 사용해서</strong> 크기가 $1, 2, \cdots , i$인 동심원을 만드는 경우의 수를 $D(i,a)$라고 정의합시다. $D(i,a) = D(i-1,a-i) + D(i-1,a)$이고, $O(A \sqrt {A+B})$에 계산할 수 있습니다.<br />위 점화식을 계산한 DP 테이블을 갖고 있다면, 문제의 정답을 계산하는 것은 간단합니다. 아래 코드는 매번 $O(A \sqrt {A+B})$ 시간이 걸리기 때문에 여전히 90점을 받는 코드입니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">Query</span><span class="p">(</span><span class="kt">int</span> <span class="n">A</span><span class="p">,</span> <span class="kt">int</span> <span class="n">B</span><span class="p">){</span> <span class="kt">int</span> <span class="n">res</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">SZ</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="kt">int</span> <span class="n">req</span> <span class="o">=</span> <span class="n">i</span> <span class="o">*</span> <span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;=</span><span class="n">A</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="k">if</span><span class="p">(</span><span class="n">req</span> <span class="o">-</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">B</span><span class="p">)</span> <span class="n">Add</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</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> </code></pre></div></div> <p>위 코드에서 <code class="language-plaintext highlighter-rouge">req - j &lt;= B</code>를 약간 변형하면 <code class="language-plaintext highlighter-rouge">req - B &lt;= j</code>가 됩니다. 그러므로 위 코드는 사실 $i$마다 $D(i,\text{req}-B)$부터 $D(i,A)$까지의 합, 즉 $D(i, \ast)$의 부분합을 구하는 코드입니다. 그러므로 DP 테이블의 각 행마다 Prefix Sum을 계산하면 Query 함수를 $O(\sqrt {A+B})$에 작성할 수 있습니다.</p> <p>전체 문제를 $O((T+AB) \sqrt {A+B})$에 해결할 수 있습니다.</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">constexpr</span> <span class="kt">int</span> <span class="n">SZ</span> <span class="o">=</span> <span class="mi">450</span><span class="p">;</span> <span class="k">constexpr</span> <span class="kt">int</span> <span class="n">MOD</span> <span class="o">=</span> <span class="mf">1e9</span><span class="o">+</span><span class="mi">7</span><span class="p">;</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">int</span> <span class="o">&amp;</span><span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">){</span> <span class="n">a</span> <span class="o">+=</span> <span class="n">b</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">a</span> <span class="o">&gt;=</span> <span class="n">MOD</span><span class="p">)</span> <span class="n">a</span> <span class="o">-=</span> <span class="n">MOD</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="n">D</span><span class="p">[</span><span class="n">SZ</span><span class="p">][</span><span class="mi">50001</span><span class="p">];</span> <span class="kt">int</span> <span class="nf">Sum</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">s</span><span class="p">,</span> <span class="kt">int</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">&gt;</span> <span class="n">e</span><span class="p">)</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="kt">int</span> <span class="n">res</span> <span class="o">=</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">e</span><span class="p">]</span> <span class="o">-</span> <span class="p">(</span><span class="n">s</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">?</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">s</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="k">return</span> <span class="n">res</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">?</span> <span class="n">res</span> <span class="o">:</span> <span class="n">res</span> <span class="o">+</span> <span class="n">MOD</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">D</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">SZ</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">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">50000</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">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="k">if</span><span class="p">(</span><span class="n">j</span> <span class="o">-</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="n">Add</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">],</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</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="p">}</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">SZ</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="k">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="mi">50000</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="n">Add</span><span class="p">(</span><span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">],</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">]);</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">Query</span><span class="p">(</span><span class="kt">int</span> <span class="n">A</span><span class="p">,</span> <span class="kt">int</span> <span class="n">B</span><span class="p">){</span> <span class="kt">int</span> <span class="n">res</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">SZ</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="kt">int</span> <span class="n">req</span> <span class="o">=</span> <span class="n">i</span> <span class="o">*</span> <span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span> <span class="n">Add</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">Sum</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">req</span> <span class="o">-</span> <span class="n">B</span><span class="p">,</span> <span class="n">A</span><span class="p">));</span> <span class="p">}</span> <span class="k">return</span> <span class="n">res</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="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">Init</span><span class="p">();</span> <span class="k">while</span><span class="p">(</span><span class="n">T</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">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">cout</span> <span class="o">&lt;&lt;</span> <span class="n">Query</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">&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="p">}</span> </code></pre></div></div> <h3 id="2번">2번</h3> <p>정점 $u$에 배정된 가중치를 $x$라고 합시다. $u$와 가중치가 $e$인 간선으로 연결된 정점 $v$에는 $e-x$가 배정되고, $v$와 가중치가 $f$인 간선으로 연결된 정점 $w$에는 $f-(e-x) = -x+(f-e)$가 배정될 것입니다. 이렇게 가중치를 배정하는 과정을 생각해보면 아래와 같은 관찰을 할 수 있습니다.</p> <p><strong>한 정점의 가중치를 $x$라고 하면, 다른 모든 정점의 가중치를 $x+b$ 혹은 $-x+b$ 꼴로 표현할 수 있다.</strong></p> <p>위 관찰을 통해, $ax+b$ 꼴의 일차 함수가 $N$개 주어졌을 때 $\vert ax+b \vert$의 합을 최소로 하는 $x$를 찾는 문제고 바꿀 수 있습니다. (단, $\vert a \vert$ = 1) 먼저 일차 함수 $N$개를 찾는 방법을 알아봅시다.</p> <p>임의의 정점 $v$를 잡은 뒤, $v$의 함수를 $1x+0(=x)$로 설정합시다. $v$부터 DFS를 하면서, 만약 $ax+b$를 함수로 갖는 $u$와 $w$가 가중치가 $e$인 간선으로 연결되어 있다면 $w$의 함수를 $-ax + (e-b)$로 설정합니다. 만약 그래프에 사이클이 없다면 이 과정이 순조롭게 진행되겠지만, 사이클이 있는 경우에는 몇 가지 문제가 발생하게 됩니다.</p> <p>기존에 방문했던 정점 $c$로 돌아온 상황을 가정해봅시다. 또한, 기존에 구한 $c$의 함수를 $ax+b$, 이번에 새로 구한 함수를 $a’x+b’$이라고 합시다. 3가지 경우로 나눌 수 있습니다.</p> <ol> <li>$(a, b) = (a’, b’)$ : 동일한 정보가 들어온 경우입니다. 추가적인 처리 없이 넘어가면 됩니다.</li> <li>$a = a’ \land b \neq b’$ : $ax+b = a’x+b’$이 성립하는 $x$가 존재하지 않습니다. 모순이 생긴 것이므로 <code class="language-plaintext highlighter-rouge">No</code>를 출력하고 프로그램을 종료합니다.</li> <li><strong>그 외의 경우</strong> : $ax+b = a’x+b’$이 성립하는 $x$가 정확히 하나 존재합니다. $x = (b’-b)/(a-a’)$이며, 어차피 $\vert a-a’ \vert = 2$이므로 2를 곱해서 저장해도 상관 없습니다.</li> </ol> <p>위 3가지 경우를 처리하며 DFS를 모두 수행하고 나면 아래 3가지 상황 중 한 가지에 놓이게 됩니다.</p> <ol> <li><strong>3번이 여러 번 발생했고, 이때 $x$를 2가지 이상 발견한 경우</strong> : 모순이 생긴 것이므로 <code class="language-plaintext highlighter-rouge">No</code>를 출력하고 프로그램을 종료합니다.</li> <li><strong>3번이 한 번 이상 발생해서 $x$를 정확히 하나 찾은 경우</strong> : $x$를 찾았으므로 문제의 정답을 구할 수 있습니다.</li> <li><strong>3번이 한 번도 발생하지 않은 경우</strong> : $\sum \vert ax+b \vert$가 최소가 되는 $x$(극점)를 직접 찾아야 합니다. 일차 함수의 절댓값은 unimodal하고, 이들의 합도 unimodal하기 때문에 <strong>삼분 탐색</strong>을 이용해 극점을 찾을 수 있습니다. 또는 $x$가 $-b/a$들의 중앙값이면 $\sum \vert ax+b \vert$가 최소가 된다는 것을 이용해 $x$를 구할 수도 있습니다.</li> </ol> <p>DFS는 $O(N+M)$에 할 수 있고, $x$를 찾는 것은 $O(N \log N)$ 정도에 가능하므로 제한 시간 내에 문제를 해결할 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; #define x first #define y second </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="k">using</span> <span class="n">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">ld</span> <span class="o">=</span> <span class="kt">long</span> <span class="kt">double</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="kr">inline</span> <span class="kt">void</span> <span class="nf">DIE</span><span class="p">(){</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"No"</span><span class="p">;</span> <span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="p">}</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">M</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">PLL</span><span class="o">&gt;</span> <span class="n">G</span><span class="p">[</span><span class="mi">101010</span><span class="p">];</span> <span class="n">PLL</span> <span class="n">A</span><span class="p">[</span><span class="mi">101010</span><span class="p">];</span> <span class="kt">bool</span> <span class="n">C</span><span class="p">[</span><span class="mi">101010</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">Fix</span><span class="p">,</span> <span class="n">Can</span><span class="p">,</span> <span class="n">Vis</span><span class="p">;</span> <span class="n">ll</span> <span class="n">R</span><span class="p">[</span><span class="mi">101010</span><span class="p">];</span> <span class="kt">void</span> <span class="nf">DFS</span><span class="p">(</span><span class="kt">int</span> <span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">mul</span><span class="p">,</span> <span class="n">ll</span> <span class="n">add</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">C</span><span class="p">[</span><span class="n">v</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="o">=</span> <span class="p">{</span><span class="n">mul</span><span class="p">,</span> <span class="n">add</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">x</span> <span class="o">==</span> <span class="n">mul</span> <span class="o">&amp;&amp;</span> <span class="n">A</span><span class="p">[</span><span class="n">v</span><span class="p">].</span><span class="n">y</span> <span class="o">==</span> <span class="n">add</span><span class="p">)</span> <span class="k">return</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">x</span> <span class="o">==</span> <span class="n">mul</span> <span class="o">&amp;&amp;</span> <span class="n">A</span><span class="p">[</span><span class="n">v</span><span class="p">].</span><span class="n">y</span> <span class="o">!=</span> <span class="n">add</span><span class="p">)</span> <span class="n">DIE</span><span class="p">();</span> <span class="k">else</span><span class="p">{</span> <span class="n">Fix</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="mi">2</span> <span class="o">*</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">y</span> <span class="o">-</span> <span class="n">add</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="n">mul</span> <span class="o">-</span> <span class="n">A</span><span class="p">[</span><span class="n">v</span><span class="p">].</span><span class="n">x</span><span class="p">));</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="n">Vis</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="n">C</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">mul</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="n">Can</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="o">-</span><span class="n">add</span><span class="p">);</span> <span class="k">else</span> <span class="n">Can</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">add</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="n">DFS</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="o">-</span><span class="n">mul</span><span class="p">,</span> <span class="n">w</span><span class="o">-</span><span class="n">add</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="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="kt">int</span> <span class="n">s</span><span class="p">,</span> <span class="n">e</span><span class="p">,</span> <span class="n">x</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">s</span> <span class="o">&gt;&gt;</span> <span class="n">e</span> <span class="o">&gt;&gt;</span> <span class="n">x</span><span class="p">;</span> <span class="n">G</span><span class="p">[</span><span class="n">s</span><span class="p">].</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">x</span><span class="p">);</span> <span class="n">G</span><span class="p">[</span><span class="n">e</span><span class="p">].</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">x</span><span class="p">);</span> <span class="p">}</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">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">C</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">Fix</span><span class="p">.</span><span class="n">clear</span><span class="p">();</span> <span class="n">Can</span><span class="p">.</span><span class="n">clear</span><span class="p">();</span> <span class="n">Vis</span><span class="p">.</span><span class="n">clear</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="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="n">sort</span><span class="p">(</span><span class="n">Can</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">Can</span><span class="p">.</span><span class="n">end</span><span class="p">());</span> <span class="n">sort</span><span class="p">(</span><span class="n">Fix</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">Fix</span><span class="p">.</span><span class="n">end</span><span class="p">());</span> <span class="n">Fix</span><span class="p">.</span><span class="n">erase</span><span class="p">(</span><span class="n">unique</span><span class="p">(</span><span class="n">Fix</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">Fix</span><span class="p">.</span><span class="n">end</span><span class="p">()),</span> <span class="n">Fix</span><span class="p">.</span><span class="n">end</span><span class="p">());</span> <span class="k">if</span><span class="p">(</span><span class="n">Fix</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">)</span> <span class="n">DIE</span><span class="p">();</span> <span class="k">if</span><span class="p">(</span><span class="n">Fix</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="o">&amp;&amp;</span> <span class="n">Fix</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="n">DIE</span><span class="p">();</span> <span class="kt">double</span> <span class="n">X</span> <span class="o">=</span> <span class="n">Fix</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="o">?</span> <span class="n">Fix</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">/</span><span class="mi">2</span> <span class="o">:</span> <span class="n">Can</span><span class="p">[</span><span class="n">Can</span><span class="p">.</span><span class="n">size</span><span class="p">()</span><span class="o">/</span><span class="mi">2</span><span class="p">];</span> <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="n">j</span> <span class="o">:</span> <span class="n">Vis</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">A</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">x</span> <span class="o">*</span> <span class="n">X</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">y</span><span class="p">;</span> <span class="p">}</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Yes</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">R</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <h3 id="3번">3번</h3> <p>문제를 10초만 쳐다보면 풀이를 알 수 있습니다. 잘 모르겠다면 Suffix Array와 Longest Common Prefix를 구하는 방법을 공부한 뒤, <a href="https://www.acmicpc.net/problem/9249">BOJ 9249 최장 공통 부분 문자열</a>을 풀어보면 됩니다. SA와 LCP를 이용해 최장 공통 부분 문자열을 구하는 방법을 응용하면 최장 공통 괄호 부분 문자열도 구할 수 있습니다.</p> <p>SA 상에서 인접한 접미사(Suffix) 간의 최장 공통 접두사(LCP)를 모두 확인합시다. 각 LCP마다 가장 긴 괄호 부분 문자열을 구하면, 이들 중 최댓값이 문제의 정답이 됩니다.</p> <p>문자열이 주어졌을 때 <a href="https://www.acmicpc.net/problem/13536">임의의 부분 문자열에서 최장 괄호 부분 문자열을 구하는 쿼리</a>는 $O(\log N)$에 할 수 있으므로 SA와 LCP를 구해놓았다면 문제를 $O(N \log N)$에 해결할 수 있습니다.</p> <p>SA와 LCP를 구하는 것은 $O(N), O(N \log N), O(N log^2 N)$ 등 여러가지 방법이 있는데, 실제 대회에 참가하지 않아서 어디까지 허용되는지 모르겠습니다. 아래 코드는 $O(N \log^2 N)$으로 구현된 코드입니다.</p> <p>해싱을 이용한 똑똑한 풀이가 있다고 하던데 저는 잘 모르겠습니다.</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="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">getSA</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">len</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">sa</span><span class="p">(</span><span class="n">n</span><span class="p">),</span> <span class="n">pos</span><span class="p">(</span><span class="n">n</span><span class="p">),</span> <span class="n">tmp</span><span class="p">(</span><span class="n">n</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">sa</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span><span class="p">,</span> <span class="n">pos</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="k">auto</span> <span class="n">compare</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">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">pos</span><span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">!=</span> <span class="n">pos</span><span class="p">[</span><span class="n">b</span><span class="p">])</span> <span class="k">return</span> <span class="n">pos</span><span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">pos</span><span class="p">[</span><span class="n">b</span><span class="p">];</span> <span class="k">if</span><span class="p">(</span><span class="n">a</span><span class="o">+</span><span class="n">len</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">&amp;&amp;</span> <span class="n">b</span><span class="o">+</span><span class="n">len</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">)</span> <span class="k">return</span> <span class="n">pos</span><span class="p">[</span><span class="n">a</span><span class="o">+</span><span class="n">len</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">pos</span><span class="p">[</span><span class="n">b</span><span class="o">+</span><span class="n">len</span><span class="p">];</span> <span class="k">return</span> <span class="n">a</span> <span class="o">&gt;</span> <span class="n">b</span><span class="p">;</span> <span class="p">};</span> <span class="k">for</span><span class="p">(</span><span class="n">len</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="p">;</span> <span class="n">len</span><span class="o">&lt;&lt;=</span><span class="mi">1</span><span class="p">){</span> <span class="n">sort</span><span class="p">(</span><span class="n">sa</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">sa</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">compare</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">+</span><span class="mi">1</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">tmp</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">tmp</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">compare</span><span class="p">(</span><span class="n">sa</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">sa</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">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">pos</span><span class="p">[</span><span class="n">sa</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span> <span class="o">=</span> <span class="n">tmp</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">tmp</span><span class="p">.</span><span class="n">back</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="k">break</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="n">move</span><span class="p">(</span><span class="n">sa</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">getLCP</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span> <span class="o">&amp;</span><span class="n">s</span><span class="p">,</span> <span class="k">const</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="o">&amp;</span><span class="n">sa</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="kt">int</span><span class="o">&gt;</span> <span class="n">pos</span><span class="p">(</span><span class="n">n</span><span class="p">),</span> <span class="n">lcp</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">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">pos</span><span class="p">[</span><span class="n">sa</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span> <span class="k">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">k</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">k</span><span class="o">=</span><span class="n">max</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="mi">0</span><span class="p">)){</span> <span class="k">if</span><span class="p">(</span><span class="n">pos</span><span class="p">[</span><span class="n">i</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="k">continue</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">sa</span><span class="p">[</span><span class="n">pos</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">+</span><span class="mi">1</span><span class="p">];</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="n">k</span><span class="p">]</span><span class="o">==</span><span class="n">s</span><span class="p">[</span><span class="n">j</span><span class="o">+</span><span class="n">k</span><span class="p">];</span> <span class="n">k</span><span class="o">++</span><span class="p">);</span> <span class="n">lcp</span><span class="p">[</span><span class="n">pos</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span> <span class="o">=</span> <span class="n">k</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="n">move</span><span class="p">(</span><span class="n">lcp</span><span class="p">);</span> <span class="p">}</span> <span class="k">struct</span> <span class="nc">Node</span><span class="p">{</span> <span class="kt">int</span> <span class="n">res</span><span class="p">,</span> <span class="n">opn</span><span class="p">,</span> <span class="n">cls</span><span class="p">;</span> <span class="kt">void</span> <span class="n">init</span><span class="p">(</span><span class="kt">char</span> <span class="n">c</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">opn</span> <span class="o">=</span> <span class="n">c</span> <span class="o">==</span> <span class="sc">'('</span><span class="p">;</span> <span class="n">cls</span> <span class="o">=</span> <span class="sc">')'</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="n">T</span><span class="p">[</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="mi">21</span><span class="p">];</span> <span class="n">Node</span> <span class="nf">Merge</span><span class="p">(</span><span class="k">const</span> <span class="n">Node</span> <span class="o">&amp;</span><span class="n">l</span><span class="p">,</span> <span class="k">const</span> <span class="n">Node</span> <span class="o">&amp;</span><span class="n">r</span><span class="p">){</span> <span class="kt">int</span> <span class="n">add</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">l</span><span class="p">.</span><span class="n">opn</span><span class="p">,</span> <span class="n">r</span><span class="p">.</span><span class="n">cls</span><span class="p">);</span> <span class="k">return</span> <span class="p">{</span> <span class="n">l</span><span class="p">.</span><span class="n">res</span> <span class="o">+</span> <span class="n">r</span><span class="p">.</span><span class="n">res</span> <span class="o">+</span> <span class="n">add</span><span class="o">*</span><span class="mi">2</span><span class="p">,</span> <span class="n">l</span><span class="p">.</span><span class="n">opn</span> <span class="o">+</span> <span class="n">r</span><span class="p">.</span><span class="n">opn</span> <span class="o">-</span> <span class="n">add</span><span class="p">,</span> <span class="n">l</span><span class="p">.</span><span class="n">cls</span> <span class="o">+</span> <span class="n">r</span><span class="p">.</span><span class="n">cls</span> <span class="o">-</span> <span class="n">add</span> <span class="p">};</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">Build</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="k">const</span> <span class="n">string</span> <span class="o">&amp;</span><span class="n">str</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="n">init</span><span class="p">(</span><span class="n">str</span><span class="p">[</span><span class="n">s</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="n">s</span> <span class="o">+</span> <span class="n">e</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span> <span class="n">Build</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">str</span><span class="p">);</span> <span class="n">Build</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">str</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">Node</span> <span class="nf">Query</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="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="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="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">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="n">s</span> <span class="o">+</span> <span class="n">e</span> <span class="o">&gt;&gt;</span> <span class="mi">1</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">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">l</span><span class="p">,</span> <span class="n">r</span><span class="p">),</span> <span class="n">Query</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">l</span><span class="p">,</span> <span class="n">r</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">string</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</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">string</span> <span class="n">s</span> <span class="o">=</span> <span class="n">a</span> <span class="o">+</span> <span class="s">"$"</span> <span class="o">+</span> <span class="n">b</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">A</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">B</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="k">auto</span> <span class="n">sa</span> <span class="o">=</span> <span class="n">getSA</span><span class="p">(</span><span class="n">s</span><span class="p">),</span> <span class="n">lcp</span> <span class="o">=</span> <span class="n">getLCP</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">sa</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">pos</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="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">pos</span><span class="p">[</span><span class="n">sa</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span> <span class="n">Build</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">N</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="kt">int</span> <span class="n">res</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">+</span><span class="mi">1</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">sa</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">A</span> <span class="o">||</span> <span class="n">sa</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">A</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span> <span class="k">if</span><span class="p">((</span><span class="n">sa</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">A</span><span class="p">)</span> <span class="o">==</span> <span class="p">(</span><span class="n">sa</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">A</span><span class="p">))</span> <span class="k">continue</span><span class="p">;</span> <span class="kt">int</span> <span class="n">st</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">sa</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">sa</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">len</span> <span class="o">=</span> <span class="n">lcp</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="kt">int</span> <span class="n">now</span> <span class="o">=</span> <span class="n">Query</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">N</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">st</span><span class="p">,</span> <span class="n">st</span><span class="o">+</span><span class="n">len</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">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">now</span><span class="p">);</span> <span class="p">}</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">res</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="kt">int</span> <span class="n">TC</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">TC</span><span class="p">;</span> <span class="k">while</span><span class="p">(</span><span class="n">TC</span><span class="o">--</span><span class="p">)</span> <span class="n">Solve</span><span class="p">();</span> <span class="p">}</span> </code></pre></div></div>JusticeHui문제 감상백준17752 Messenger2021-05-25T01:50:00+00:002021-05-25T01:50:00+00:00https://justicehui.github.io/joisc/2021/05/25/BOJ17752<h3 id="문제-링크">문제 링크</h3> <ul> <li>http://icpc.me/17752</li> </ul> <h3 id="문제-출처">문제 출처</h3> <ul> <li>2012/2013 JOI Spring Camp Day4 1번</li> </ul> <h3 id="풀이">풀이</h3> <p>작년 여름에 풀지 못한 이후로 계속 출처를 찾아 헤매다 1년 만에 출처를 찾아서 풀었습니다. OI 문제라는 확신을 갖고 ojuz의 모든 인터랙티브/투스텝 문제를 뒤져보았지만 못 찾았었는데, 아직 ojuz에 안 올라왔더군요…</p> <h4 id="문제-요약">문제 요약</h4> <p>A와 B는 서로 다른 방에 있고, 복도에 4-by-4 크기의 체스판과 체스말 하나가 있습니다. A에게 어떤 자연수 X가 주어지면 복도에 있는 체스판과 체스말을 이용해서 B에게 X를 알려주어야 합니다.<br /> 진행 방식은 다음과 같습니다.</p> <ol> <li>A와 B가 각각 복도에 나올 순서를 나타내는 <code class="language-plaintext highlighter-rouge">A</code>, <code class="language-plaintext highlighter-rouge">B</code>로 구성된 문자열 <code class="language-plaintext highlighter-rouge">S</code>는 이미 정해져 있습니다.(grader에 입력으로 주어집니다.) 길이는 정확히 <code class="language-plaintext highlighter-rouge">10 000</code>이며, 같은 문자가 100번보다 많이 연달아 나오는 경우는 없습니다.</li> <li><code class="language-plaintext highlighter-rouge">InitA(T, X)</code>와 <code class="language-plaintext highlighter-rouge">InitB(T)</code>가 호출됩니다. <code class="language-plaintext highlighter-rouge">T</code>는 테스트케이스 번호를, <code class="language-plaintext highlighter-rouge">X(≤ 1 000 000 000)</code>는 A가 B에게 전달해야 할 수를 의미합니다.</li> <li>문자열 <code class="language-plaintext highlighter-rouge">S</code>에 따라 A 혹은 B가 복도로 나와 체스말을 인접한 칸으로 이동합니다. <ul> <li>A가 이동할 차례라면 <code class="language-plaintext highlighter-rouge">GameA(I, J)</code>가 호출되며, 이때 <code class="language-plaintext highlighter-rouge">I</code>, <code class="language-plaintext highlighter-rouge">J</code>는 현재 체스판의 위치(행, 열)를 의미합니다.</li> <li>B가 이동할 차례라면 <code class="language-plaintext highlighter-rouge">GameB(I, J)</code>가 호출됩니다.</li> <li>체스판을 위/아래/왼쪽/오른쪽으로 이동할 경우 각각 <code class="language-plaintext highlighter-rouge">-1</code>/<code class="language-plaintext highlighter-rouge">-2</code>/<code class="language-plaintext highlighter-rouge">-3</code>/<code class="language-plaintext highlighter-rouge">-4</code>를 반환합니다.</li> <li><code class="language-plaintext highlighter-rouge">GameB</code>가 호출되는 시점에 정답을 알아냈다면 정답을 반환하면 됩니다.</li> </ul> </li> </ol> <h4 id="풀이-1">풀이</h4> <p>한 번의 이동으로 얼마나 많은 정보를 전달할 수 있을까요? (1) A가 한 번 이동하고 B가 그것을 확인한 것과 (2) A가 100번 이동하고 B가 그것을 확인한 것이 모두 동일한 취급을 받는 것에 주의해야 합니다. 가장 먼저 생각해볼 수 있는 것은 <strong>비트 단위로 전송</strong>하는 것입니다. <code class="language-plaintext highlighter-rouge">GameA</code>와 <code class="language-plaintext highlighter-rouge">GameB</code>가 각각 최소한 90번 이상 호출되기 때문에 충분히 10억 이하(30비트 이하)의 정수를 전송할 수 있습니다.</p> <p>잠시 TCP의 3 way-handshake를 생각해봅시다. 아래 과정을 통해 서버와 클라이언트 간의 동기화를 진행합니다.</p> <ol> <li>클라이언트 : “나 보낸다!” (SYN)</li> <li>서버 : “어 보내~” (SYN/ACK)</li> <li>클라이언트 : “ㅇㅋ 시작한다” (ACK)</li> </ol> <p>이 문제도 A와 B가 사전에 어떠한 <strong>규칙</strong>을 정해서, <strong>정보 전송을 시작한다는 신호</strong>를 공유해야 합니다. 문제 풀이 로직의 흐름은 아래와 같이 표현할 수 있습니다.</p> <ol> <li>A와 B가 어떠한 <strong>규칙</strong>을 통해 동기화를 합니다.</li> <li><code class="language-plaintext highlighter-rouge">GameA</code>가 호출된 경우 체스말을 적당히 옮겨서 한 비트를 전송합니다. <ul> <li><code class="language-plaintext highlighter-rouge">GameA</code>가 연달아서 호출된 경우, 체스말을 적당히 옮겨서 아무 정보를 전달하지 않습니다.</li> </ul> </li> <li><code class="language-plaintext highlighter-rouge">GameB</code>가 호출된 경우 A가 전달한 정보를 수집하고, A가 정보를 전달하기 전 상태로 복구합니다. <ul> <li><code class="language-plaintext highlighter-rouge">GameB</code>가 연달아서 호출된 경우, 체스말을 적당히 옮겨서 아무 정보를 수집하지 않고 정보를 전달하지도 않습니다.</li> </ul> </li> </ol> <p>(1) 동기화를 하는 <strong>규칙</strong>, (2) A가 정보를 전달하는 방법, (3) 어떤 함수가 연달아 호출되었을 때 아무 정보도 전달하지 않는 방법을 잘 정하면 문제를 해결할 수 있습니다. 그 중 한 가지 방법을 제시합니다.</p> <h5 id="동기화를-하는-규칙">동기화를 하는 규칙</h5> <p>2번 행에 체스말이 도달하는 것을 동기화의 시그널이라고 합시다.<br /> <code class="language-plaintext highlighter-rouge">GameA</code>가 호출되는 시점에 이미 $I = 2$라면 이때부터 A는 정보 전송을 시작합니다.</p> <h5 id="a가-정보를-전송하는-방법">A가 정보를 전송하는 방법</h5> <p>$I = 2$인 상황입니다.<br /> 만약 <code class="language-plaintext highlighter-rouge">0</code>을 전송해야 한다면 위로 이동하고, <code class="language-plaintext highlighter-rouge">1</code>을 전송해야 한다면 아래로 이동합니다.</p> <p><code class="language-plaintext highlighter-rouge">GameB</code>가 호출되는 시점에 $I = 1$이라면 <code class="language-plaintext highlighter-rouge">0</code>을 전달받은 것이고, $I = 3$이라면 <code class="language-plaintext highlighter-rouge">1</code>을 전달받은 것입니다. 정보를 수집하고 다시 체스말을 2번 행으로 옮겨줍시다.</p> <h5 id="아무-정보도-전달하지-않는-방법">아무 정보도 전달하지 않는 방법</h5> <p>행 번호를 매개로 정보를 전달하기 때문에, 같은 행에서 움직이는 것은 정보 전달에 아무 영향도 미치지 않습니다. 왼쪽/오른쪽으로 이동하면 됩니다.</p> <p>아래 코드는 구현의 편의를 위해 A와 B가 서로 동기화하지 않고, <code class="language-plaintext highlighter-rouge">GameA</code>가 호출되는 시점에 $I = 2$라면 일방적으로 정보를 전송합니다. 구체적인 방법은 코드(특히 <code class="language-plaintext highlighter-rouge">MX</code>, <code class="language-plaintext highlighter-rouge">MX+1</code> 부분)를 참고해주세요.</p> <h3 id="전체-코드">전체 코드</h3> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><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">U</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">D</span> <span class="o">=</span> <span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="n">L</span> <span class="o">=</span> <span class="o">-</span><span class="mi">3</span><span class="p">,</span> <span class="n">R</span> <span class="o">=</span> <span class="o">-</span><span class="mi">4</span><span class="p">,</span> <span class="n">MX</span> <span class="o">=</span> <span class="mi">31</span><span class="p">;</span> <span class="k">namespace</span> <span class="n">A</span><span class="p">{</span> <span class="n">ll</span> <span class="n">ans</span><span class="p">;</span> <span class="kt">int</span> <span class="n">bit</span><span class="p">;</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">InitA</span><span class="p">(</span><span class="kt">int</span> <span class="n">T</span><span class="p">,</span> <span class="kt">int</span> <span class="n">X</span><span class="p">){</span> <span class="n">A</span><span class="o">::</span><span class="n">ans</span> <span class="o">=</span> <span class="n">X</span> <span class="o">|</span> <span class="p">(</span><span class="mi">1U</span> <span class="o">&lt;&lt;</span> <span class="n">MX</span><span class="p">);</span> <span class="n">A</span><span class="o">::</span><span class="n">bit</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">GameA</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">if</span><span class="p">(</span><span class="n">I</span> <span class="o">==</span> <span class="mi">4</span><span class="p">)</span> <span class="k">return</span> <span class="n">U</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">I</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">||</span> <span class="n">I</span> <span class="o">==</span> <span class="mi">3</span><span class="p">)</span> <span class="k">return</span> <span class="n">J</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">?</span> <span class="n">R</span> <span class="o">:</span> <span class="n">L</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">A</span><span class="o">::</span><span class="n">ans</span> <span class="o">&amp;</span> <span class="p">(</span><span class="mi">1LL</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">A</span><span class="o">::</span><span class="n">bit</span><span class="o">++</span><span class="p">)))</span> <span class="k">return</span> <span class="n">D</span><span class="p">;</span> <span class="k">return</span> <span class="n">U</span><span class="p">;</span> <span class="p">}</span> <span class="k">namespace</span> <span class="n">B</span><span class="p">{</span> <span class="n">ll</span> <span class="n">ans</span><span class="p">;</span> <span class="kt">int</span> <span class="n">bit</span><span class="p">;</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">InitB</span><span class="p">(</span><span class="kt">int</span> <span class="n">T</span><span class="p">){</span> <span class="n">B</span><span class="o">::</span><span class="n">ans</span> <span class="o">=</span> <span class="n">B</span><span class="o">::</span><span class="n">bit</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">GameB</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">if</span><span class="p">(</span><span class="n">I</span> <span class="o">==</span> <span class="mi">4</span><span class="p">)</span> <span class="k">return</span> <span class="n">U</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">I</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span> <span class="k">return</span> <span class="n">J</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">?</span> <span class="n">R</span> <span class="o">:</span> <span class="n">L</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">I</span> <span class="o">==</span> <span class="mi">1</span><span class="p">){</span> <span class="n">B</span><span class="o">::</span><span class="n">bit</span><span class="o">++</span><span class="p">;</span> <span class="k">return</span> <span class="n">D</span><span class="p">;</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">B</span><span class="o">::</span><span class="n">bit</span> <span class="o">==</span> <span class="n">MX</span><span class="p">)</span> <span class="k">return</span> <span class="n">B</span><span class="o">::</span><span class="n">ans</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="n">bit</span> <span class="o">==</span> <span class="n">MX</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="k">return</span> <span class="n">B</span><span class="o">::</span><span class="n">ans</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span> <span class="n">B</span><span class="o">::</span><span class="n">ans</span> <span class="o">|=</span> <span class="p">(</span><span class="mi">1LL</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">B</span><span class="o">::</span><span class="n">bit</span><span class="o">++</span><span class="p">));</span> <span class="k">return</span> <span class="n">U</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div>JusticeHui문제 링크 http://icpc.me/17752CMS 세팅 - 12021-05-18T21:50:00+00:002021-05-18T21:50:00+00:00https://justicehui.github.io/etc/2021/05/18/cms-1<p>앞으로 2-3개의 글을 통해 CMS로 대회를 개최하는 방법을 소개하려고 합니다.<br /> 이번 글에서는 CMS의 구조를 간단하게 소개하고, CMS를 이용해 대회를 만들고 간단한 Batch 문제를 업로드하는 방법을 소개합니다. SPJ/Grader/Interactive 문제를 업로드하는 방법과 더 정교하게 채점환경을 구축하는 것은 다음 글에서 소개하도록 하겠습니다.</p> <p>대부분의 내용은 <a href="https://cms.readthedocs.io/en/v1.4/index.html">CMS 1.4 Document</a>를 번역한 것이며, CMS 세팅 방법은 <a href="https://www.vultr.com/">vultr</a>의 Ubuntu 18.04를 기준으로 설명합니다.<br /> 제출 결과 토큰이나 코드 인쇄 등 자주 사용하지 않는 몇몇 기능은 생략했습니다.</p> <h3 id="cms-소개">CMS 소개</h3> <h4 id="개요">개요</h4> <p><a href="https://github.com/cms-dev/cms">CMS(Contest Management System)</a>는 <a href="https://ioinformatics.org/">IOI(국제정보올림피아드)</a>, <a href="https://koi.or.kr/">KOI(한국정보올림피아드)</a>와 같은 여러 프로그래밍 대회를 개최할 수 있는 소프트웨어입니다. 한국에서는 <a href="https://koi.or.kr/">한국정보올림피아드</a>와 <a href="https://ioikorea.or.kr:446/main/index.asp">국제정보올림피아드 계절학교</a>에서 사용해서 여러 학생들에게 익숙하기 때문에, 여러 소규모 대회에서도 CMS를 사용해 대회를 개최하는 모습을 볼 수 있습니다.</p> <h4 id="cms-구조">CMS 구조</h4> <p>Online Judge는 사용자에게 보여지는 웹사이트, 사용자의 제출을 하는 채점 프로그램, 대회에 관련된 전반적인 정보를 저장하는 데이터베이스 등 다양한 서비스로 구성되어 있습니다. CMS는 어떤 서비스에서 충돌이 있을 경우 빠르게 회복하고, 대회 참가자 수에 따라 쉽게 확장을 할 수 있도록 각 서비스를 모듈 형태로 설계했습니다. CMS를 구성하는 핵심 서비스는 다음과 같습니다.</p> <ul> <li><code class="language-plaintext highlighter-rouge">AdminWebServer</code> : 대회에 관련된 정보(문제, 참가자, 대회 시간 등)를 수정하는 웹서비스입니다.</li> <li><code class="language-plaintext highlighter-rouge">ContestWebServer</code> : 참가자가 대회에서 사용(문제 지문 다운로드, 정답 코드 제출 등)하는 웹서비스입니다.</li> <li><code class="language-plaintext highlighter-rouge">EvaluationService</code> : 제출에 대한 큐(Queue)를 구성하고, 제출을 컴파일하거나 채점하는 작업을 <code class="language-plaintext highlighter-rouge">Worker</code>에게 넘겨줍니다. <ul> <li><code class="language-plaintext highlighter-rouge">Worker</code> : <code class="language-plaintext highlighter-rouge">EvaluationService</code>로부터 참가자의 제출을 넘겨 받아 채점을 하는 채점기입니다.</li> </ul> </li> <li><code class="language-plaintext highlighter-rouge">ScoringService</code> : 각 제출의 채점 결과를 수집한 뒤 점수를 계산합니다.</li> <li><code class="language-plaintext highlighter-rouge">ProxyService</code> : 계산된 점수를 랭킹에 반영합니다.</li> <li><code class="language-plaintext highlighter-rouge">RankingWebServer</code> : 스코어보드를 보여주는 웹서비스입니다. 보안을 위해 CMS 코어 서비스와 <strong>다른 서버</strong>에서 작동합니다.</li> <li><code class="language-plaintext highlighter-rouge">ResourceService</code> : 모든 서비스를 관리합니다.</li> <li><code class="language-plaintext highlighter-rouge">LogService</code> : CMS에서 발생하는 모든 로그를 수집합니다.</li> </ul> <p><code class="language-plaintext highlighter-rouge">ResourceService</code>, <code class="language-plaintext highlighter-rouge">ContestWebServer</code>, <code class="language-plaintext highlighter-rouge">Worker</code>는 대회의 규모에 따라 여러 개를 동시에 작동시킬 수 있습니다. 만약 여러 개의 서버에서 서비스를 실행한다면, 모든 서버에서 <code class="language-plaintext highlighter-rouge">ResourceService</code>를 실행해야 합니다.<br /> 예를 들어 테스트케이스(채점 데이터)가 많다면 한 번에 여러 테스트케이스를 채점하기 위해 여러 개의 <code class="language-plaintext highlighter-rouge">Worker</code>를 사용해야 합니다. 만약 참가자가 굉장히 많은 경우, 홈페이지를 그리는 것 또한 부담이 많이 되기 때문에 <code class="language-plaintext highlighter-rouge">ContestWebServer</code>를 여러 개 실행시켜 홈페이지 랜더링에 가해지는 부하를 줄일 수 있습니다.</p> <p>RankingWebServer는 DB에 직접 접근할 수 있는 서비스의 수를 제한하기 위해 의도적으로 CMS의 코어 서비스와 분리되어 있습니다. 그러므로 ProxyService로 부터 정보를 넘겨 받아 스코어보드를 갱신합니다.</p> <p>대회의 진행 상태는 모두 PostgreSQL DB에 저장됩니다. 그렇기 때문에 DB가 정상적으로 작동하는 한 다른 모든 서비스는 독립적으로 시작하고 중지할 수 있습니다. 다시 말해, CMS는 DB에 의존하기 때문에 DB가 손상되면 신속하게 조치를 취해야 합니다.</p> <h3 id="cms-설치와-실행">CMS 설치와 실행</h3> <p>한 서버에서 모든 서비스를 실행하는 방법을 다룹니다. 만약 CMS를 여러 개의 서버에 분산시켜서 실행하고 싶다면 <strong>실제 대회 열어보기</strong> 문단을 참고해주세요.</p> <h4 id="cms-소스코드-다운로드">CMS 소스코드 다운로드</h4> <blockquote> <p>wget -c https://github.com/cms-dev/cms/releases/download/v1.4.rc1/v1.4.rc1.tar.gz</p> <p>tar -zxvf v1.4.rc1.tar.gz</p> <p>cd cms</p> </blockquote> <h4 id="필요한-패키지-설치">필요한 패키지 설치</h4> <h5 id="cms에서-사용하는-패키지-설치">CMS에서 사용하는 패키지 설치</h5> <blockquote> <p>sudo apt install build-essential openjdk-8-jdk-headless fp-compiler postgresql postgresql-client python3.6 cppreference-doc-en-html cgroup-lite libcap-dev zip</p> </blockquote> <p><code class="language-plaintext highlighter-rouge">Do you want to continue?</code>가 나올 경우 <code class="language-plaintext highlighter-rouge">Y</code>를 선택하면 됩니다.</p> <h5 id="파이썬-모듈-다운로드">파이썬 모듈 다운로드</h5> <blockquote> <p>sudo apt install python3.6-dev libpq-dev libcups2-dev libyaml-dev libffi-dev python3-pip</p> <p>sudo pip3 install -r requirements.txt</p> <p>sudo python3 setup.py install</p> </blockquote> <h4 id="config-파일-수정">config 파일 수정</h4> <h5 id="config-파일-생성">config 파일 생성</h5> <blockquote> <p>cd config</p> <p>cp cms.conf.sample cms.conf</p> <p>cp cms.ranking.conf.sample cms.ranking.conf</p> </blockquote> <h5 id="config-파일-수정-1">config 파일 수정</h5> <p><code class="language-plaintext highlighter-rouge">cms.conf</code> 수정</p> <blockquote> <p>59번째 줄에서 <code class="language-plaintext highlighter-rouge">your_password_here</code>을 적당한 문자열로 수정 (DB 계정 비밀번호로 사용)</p> </blockquote> <p>(스코어보드가 필요하다면) <code class="language-plaintext highlighter-rouge">cms.ranking.conf</code> 수정</p> <blockquote> <p>cms.conf 159번째 줄에서 <code class="language-plaintext highlighter-rouge">usern4me</code>과 <code class="language-plaintext highlighter-rouge">passw0rd</code>를 적당한 문자열로 수정</p> <p>cms.ranking.conf 12, 13번째 줄에 위에서 설정한 <code class="language-plaintext highlighter-rouge">usern4me</code>과 <code class="language-plaintext highlighter-rouge">passw0rd</code> 입력</p> <p>cd ..</p> </blockquote> <h5 id="config-수정-사항-적용">config 수정 사항 적용</h5> <p><strong>(주의) conf 파일을 수정한 뒤에는 아래 명령을 반드시 실행해야 합니다.</strong></p> <blockquote> <p>sudo python3 ./prerequisites.py install</p> <p>만약 root유저라면 sudo python3 ./prerequisites.py –as-root install</p> </blockquote> <h4 id="db-설정">DB 설정</h4> <blockquote> <p>sudo su - postgres</p> <p>createuser –username=postgres –pwprompt cmsuser</p> <p>(이후 cms.conf에 입력한 DB 비밀번호 입력)</p> <p>createdb –username=postgres –owner=cmsuser cmsdb</p> <p>psql –username=postgres –dbname=cmsdb –command=’ALTER SCHEMA public OWNER TO cmsuser’</p> <p>psql –username=postgres –dbname=cmsdb –command=’GRANT SELECT ON pg_largeobject TO cmsuser’</p> <p>exit</p> <p>cmsInitDB</p> </blockquote> <h4 id="screen-설치">Screen 설치</h4> <p>CMS는 여러 서비스를 동시에 돌려야 하며, 각 작업은 포그라운드에서 돌아가기 때문에 한 서비스를 실행하면 콘솔을 사용하지 못하게 됩니다. 따라서 screen을 이용해 각 서비스를 서로 다른 screen에 올려서 실행할 것입니다.</p> <blockquote> <p>sudo apt-get install screen</p> </blockquote> <h4 id="cms-실행">CMS 실행</h4> <h5 id="어드민-계정-생성">어드민 계정 생성</h5> <blockquote> <p>cmsAddAdmin 어드민아이디</p> </blockquote> <p><code class="language-plaintext highlighter-rouge">Admin with complete access added. Login with username admin and password 000000</code> 형태로 나오는 비밀 번호를 기억하세요.</p> <h5 id="adminwebserver-실행-포트-기본값--8889">AdminWebServer 실행 (포트 기본값 : 8889)</h5> <blockquote> <p>screen -S AWS</p> <p>cmsAdminWebServer</p> </blockquote> <p>ctrl+A D를 이용해 스크린에서 빠져나올 수 있습니다.</p> <h5 id="logservice-실행">LogService 실행</h5> <blockquote> <p>screen -S Log</p> <p>cmsLogService</p> </blockquote> <p>ctrl+A D를 이용해 스크린에서 빠져나올 수 있습니다.</p> <h4 id="대회-생성">대회 생성</h4> <p>AdminWeb(기본값: <code class="language-plaintext highlighter-rouge">http://아이피:8889</code>)에서 대회를 만들면 <code class="language-plaintext highlighter-rouge">/contest/x</code> 형태의 URL이 나옵니다. 이때 <code class="language-plaintext highlighter-rouge">x</code>가 대회의 ID입니다.<br /> 아래 명령어를 실행하면 대회 진행을 위해 필요한 서비스들이 모두 실행됩니다. ContestWebServer(CWS)의 포트 기본값은 8888입니다.</p> <blockquote> <p>screen -S Resource</p> <p>cmsResourceService -a x (x는 정수)</p> </blockquote> <p>ctrl+A D를 이용해 스크린에서 빠져나올 수 있습니다.</p> <h3 id="대회-설정">대회 설정</h3> <p>대회는 제한 시간, 문제, 참가자 등으로 구성됩니다. 각종 설정 방법을 알아봅시다.<br /> 실제로 문제를 업로드하고 채점하는 것은 아래 <strong>실제 대회 열어보기</strong> 문단을 참고해주세요.</p> <h4 id="대회-파라미터-설정">대회 파라미터 설정</h4> <p><code class="language-plaintext highlighter-rouge">/contest/대회ID</code>에 들어가면 가장 먼저 볼 수 있는 <code class="language-plaintext highlighter-rouge">Contest configuration</code>탭에서 대회와 관련된 각종 파라미터를 설정할 수 있습니다.</p> <p><code class="language-plaintext highlighter-rouge">Token</code>은 약 10년 전 IOI에서 사용된 것으로 알고 있는데 요즘은 사용하지 않습니다. 궁금하신 분들은 공식 문서를 참고해주세요.</p> <p><code class="language-plaintext highlighter-rouge">Start time</code>과 <code class="language-plaintext highlighter-rouge">End time</code>은 말 그대로 대회 시작/종료 시간을 의미합니다. UTC 기준으로 입력해야 하는 것에 주의하세요. 만약 USACO처럼 Timeframe 방식으로 대회를 열고 싶다면 <code class="language-plaintext highlighter-rouge">Length of the contest</code>에 대회 시간을 <strong>초 단위</strong>로 입력하면 됩니다.</p> <p><code class="language-plaintext highlighter-rouge">Analysis mode</code>는 대회가 끝난 뒤(<code class="language-plaintext highlighter-rouge">End time</code> 이후) 업솔빙 용도로 제출을 열어두는 것입니다. 대회 결과에는 반영되지 않습니다. <code class="language-plaintext highlighter-rouge">Analysis mode</code>를 대회 종료 직후에 바로 시작하는 것은 권장하지 않습니다. 아래 <strong>참가자 설정</strong> 문단을 참고하세요.</p> <p>Timezone을 <code class="language-plaintext highlighter-rouge">Asia/Seoul</code>로 설정합시다.</p> <h4 id="참가자-설정">참가자 설정</h4> <p>AdminWeb의 홈으로 돌아간 다음, 좌측 탭에서 <code class="language-plaintext highlighter-rouge">create new user</code>를 클릭하면 참가자를 추가할 수 있습니다. Timezone을 적당히(한국: <code class="language-plaintext highlighter-rouge">Asia/Seoul</code>) 설정합시다.<br /> 해당 유저를 대회 참가자로 등록하고 싶다면, 해당 대회에 들어간 뒤 <code class="language-plaintext highlighter-rouge">users &gt; Select a new user</code>에서 유저를 추가하면 됩니다.</p> <p><code class="language-plaintext highlighter-rouge">delay time/extra time</code>을 이용해 하드웨어 이슈 등 일부 참가자에게 문제가 발생했을 때 대회 시작 시간/종료 시간을 <strong>초 단위</strong>로 미룰 수 있습니다. <code class="language-plaintext highlighter-rouge">Delay/Extra time</code>을 이용해서 어떤 참가자의 대회 종료가 늦어질 경우, <strong>해당 참가자</strong>만 <code class="language-plaintext highlighter-rouge">Analysis mode</code>가 늦게 시작합니다.</p> <h4 id="문제-종류">문제 종류</h4> <h4 id="batch">Batch</h4> <p>stdin/stdout을 이용하는 일반적인 문제입니다.<br /> 정답이 하나라면 <code class="language-plaintext highlighter-rouge">white-diff</code>를 사용하여 채점하면 되고, 정답이 여러 개 존재할 수 있다면 참가자의 출력이 정답인지 확인하는 프로그램(스페셜 저지)인 <code class="language-plaintext highlighter-rouge">checker</code>를 작성해야 합니다.</p> <h4 id="batch-with-grader">Batch with Grader</h4> <p>Programmers에서 주로 볼 수 있는 함수 구현 문제입니다. 참가자는 출제자가 제공하는 <code class="language-plaintext highlighter-rouge">grader.cpp</code>파일을 이용해 실행 결과를 확인할 수 있습니다.<br /> 채점 방식으로 <code class="language-plaintext highlighter-rouge">white-diff</code>와 <code class="language-plaintext highlighter-rouge">checker</code> 중 하나를 선택할 수 있습니다.</p> <h4 id="oouputonly">OouputOnly</h4> <p>코드가 아닌 출력 결과를 제출하는 문제입니다. <code class="language-plaintext highlighter-rouge">white-diff</code>나 <code class="language-plaintext highlighter-rouge">checker</code>를 이용해 채점할 수 있습니다.</p> <h4 id="communicationinteractive">Communication(Interactive)</h4> <p><a href="https://cms.readthedocs.io/en/v1.4/Task%20types.html#communication">공식 문서</a>를 참고하세요.</p> <h4 id="점수-산출-방식">점수 산출 방식</h4> <p>각 문제의 점수를 산출하는 방식에는 3가지가 있습니다.</p> <ul> <li><code class="language-plaintext highlighter-rouge">IOI 2010-2012</code> : 토큰을 사용한 제출들과 가장 마지막 제출 중 점수 최댓값</li> <li><code class="language-plaintext highlighter-rouge">IOI 2013-2016</code> : 모든 제출 중 점수 최댓값</li> <li><code class="language-plaintext highlighter-rouge">IOI 2017-</code> : 모든 제출에서 각 서브태스크 점수의 최댓값의 합집합</li> </ul> <table> <thead> <tr> <th> </th> <th>Token?</th> <th>Subtask 1</th> <th>Subtask 2</th> <th>Subtask 3</th> <th>Total</th> </tr> </thead> <tbody> <tr> <td>Submission 1</td> <td>X</td> <td>10</td> <td>0</td> <td>0</td> <td>10</td> </tr> <tr> <td>Submission 2</td> <td>O</td> <td>0</td> <td>45</td> <td>35</td> <td>80</td> </tr> <tr> <td>Submission 3</td> <td>O</td> <td>5</td> <td>50</td> <td>30</td> <td>85</td> </tr> <tr> <td>Submission 4</td> <td>X</td> <td>5</td> <td>50</td> <td>40</td> <td>95</td> </tr> <tr> <td>Submission 5</td> <td>X</td> <td>0</td> <td>45</td> <td>35</td> <td>80</td> </tr> </tbody> </table> <ul> <li><code class="language-plaintext highlighter-rouge">IOI 2010-2012</code> 방식의 경우, 토큰을 사용한 2/3번 제출과 가장 마지막 제출인 5번 제출 중 점수가 가장 큰 <strong>3번 제출(85점)</strong>이 최종 점수가 됩니다.</li> <li><code class="language-plaintext highlighter-rouge">IOI 2013-2016</code> 방식의 경우, 모든 제출 중 점수가 가장 큰 <strong>4번 제출(95점)</strong>이 최종 점수가 됩니다.</li> <li><code class="language-plaintext highlighter-rouge">IOI 2017-</code> 방식의 경우, <strong>Subtask 1</strong>에서는 1번 제출(10점), <strong>Subtask 2</strong>에서는 3번 제출(50점), <strong>Subtask 3</strong>에서는 4번 제출(40점)이 적용되어 최종 점수는 <strong>100점</strong>입니다.</li> </ul> <p>최근에 개최되는 대부분의 대회는 <code class="language-plaintext highlighter-rouge">IOI 2017-</code> 방식을 사용합니다.</p> <h3 id="실제-대회-열어보기">실제 대회 열어보기</h3> <h4 id="서버-구성">서버 구성</h4> <p>Worker를 담당할 채점 서버 2대, RankingWebServer를 담당할 스코어보드 서버 1대, 다른 모든 서비스를 담당할 메인 서버 1대를 사용할 것입니다.<br /> 메인 서버는 <a href="https://www.vultr.com/products/cloud-compute/">Vultr Cloud Compute</a>(4CPU/8GB)를, 스코어보드 서버는 <a href="https://www.vultr.com/products/cloud-compute/">Vultr Cloud Compute</a>(2CPU/4GB)를, 채점 서버는 <a href="https://www.vultr.com/products/high-frequency-compute/">Vultr High Frequency Compute</a>(2CPU/4GB)를 사용할 것입니다. 운영체제는 모두 Ubuntu 18.04를 사용합니다.</p> <p>CMS v1.4는 C++11만 지원하기 때문에 C++17 관련 설정 작업도 같이 해야합니다.</p> <h4 id="메인-서버-설정">메인 서버 설정</h4> <p>CMS 소스코드를 다운로드합시다.</p> <blockquote> <p>wget -c https://github.com/cms-dev/cms/releases/download/v1.4.rc1/v1.4.rc1.tar.gz</p> <p>tar -zxvf v1.4.rc1.tar.gz</p> <p>cd cms</p> </blockquote> <p>CMS v1.4는 C++11만 지원합니다. C++17로 바꿔줍시다.</p> <blockquote> <p>cd cms/grading/languages</p> <p>vim cpp11_gpp.py</p> <blockquote> <p>32/35번째 줄에서 <code class="language-plaintext highlighter-rouge">Cpp11Gpp</code>을 <code class="language-plaintext highlighter-rouge">Cpp17Gpp</code>로 수정</p> <p>37/44번째 줄에서 <code class="language-plaintext highlighter-rouge">C++11</code>을 <code class="language-plaintext highlighter-rouge">C++17</code>로 수정</p> <p>68번째 줄에서 <code class="language-plaintext highlighter-rouge">-std=gnu++11</code>을 <code class="language-plaintext highlighter-rouge">-std=gnu++17</code>로 수정</p> </blockquote> <p>mv cpp11_gpp.py cpp17_gpp.py</p> <p>cd ../../..</p> <p>vim setup.py</p> <blockquote> <p>196번째 줄에서 모든 <code class="language-plaintext highlighter-rouge">11</code>을 <code class="language-plaintext highlighter-rouge">17</code>로 변경</p> </blockquote> </blockquote> <p>config 파일을 수정합시다.</p> <blockquote> <p>cd config</p> <p>cp cms.conf.sample cms.conf</p> <p>cp cms.ranking.conf.sample cms.ranking.conf</p> <p>vim cms.conf</p> <blockquote> <p>28-41번 줄을 삭제합니다. (Worker를 2개만 사용합니다.)</p> <p>27번째 줄의 localhost를 <strong>1번 채점 서버의 아이피</strong>로 바꿔줍니다.</p> <p>28번째 줄의 localhost를 <strong>2번 채점 서버의 아이피</strong>로 바꿔줍니다.</p> <p>22/23/24/25/26/29/30/31/32/37/45번째 줄의 localhost를 <strong>메인 서버의 아이피</strong>로 바꿔줍니다.</p> <p>45번째 줄에서 DB 비밀번호를 설정합니다. pw라고 합시다.</p> <p>145번째 줄의 localhost를 <strong>스코어보드 서버의 아이피</strong>로 바꿔줍니다.</p> <p>145번째 줄에서 스코어보드 통신 아이디/비밀번호를 설정합니다. user / pw라고 합시다.</p> </blockquote> <p>vim cms.ranking.conf</p> <blockquote> <p>12/13번째 줄에서 username과 password를 cms.conf에서 설정한 스코어보드 통신 아이디/비밀번호로 지정 (user / pw)</p> </blockquote> <p>cd ..</p> </blockquote> <p>모든 서버에서 일일이 수정하는 것은 귀찮기 때문에, 메인 서버에서 수정한 cms 폴더를 통째로 다른 서버에 전송할 것입니다. scp를 이용해 cms 폴더를 전송합시다.</p> <blockquote> <p>scp -r ../cms root@아이피:~/</p> </blockquote> <p>필요한 패키지를 설치하고 config 파일을 적용합시다.</p> <blockquote> <p>sudo apt install build-essential openjdk-8-jdk-headless fp-compiler postgresql postgresql-client python3.6 cppreference-doc-en-html cgroup-lite libcap-dev zip</p> <p>sudo apt install python3.6-dev libpq-dev libcups2-dev libyaml-dev libffi-dev python3-pip</p> <p>sudo pip3 install -r requirements.txt</p> <p>sudo python3 setup.py install</p> <p>sudo python3 ./prerequisites.py –as-root install</p> </blockquote> <p>DB 설정을 합시다. 외부 서버(스코어보드 서버, 채점 서버)에서 메인 서버의 DB에 접속할 수 있어야 하므로 postgres 설정을 조금 수정해야 합니다.</p> <blockquote> <p>sudo su - postgres</p> <p>createuser –username=postgres –pwprompt cmsuser</p> <p>(이후 cms.conf에 입력한 DB 비밀번호 입력)</p> <p>createdb –username=postgres –owner=cmsuser cmsdb</p> <p>psql –username=postgres –dbname=cmsdb –command=’ALTER SCHEMA public OWNER TO cmsuser’</p> <p>psql –username=postgres –dbname=cmsdb –command=’GRANT SELECT ON pg_largeobject TO cmsuser’</p> <p>exit</p> <p>sudo vim /etc/postgresql/10/main/postgresql.conf (postgres 버전에 차이가 있을 수 있음)</p> <blockquote> <p>58번째 줄에 listen_addresses = ‘123.456.78.90,111.222.333.44,55.666.77.8’ 처럼 사용하는 서버들의 IP를 적어줍니다.</p> </blockquote> <p>sudo vim /etc/postgresql/10/main/pg_hba.conf</p> <blockquote> <p>모든 서버에 대해, host cmsdb cmsuser 서버IP/32 md5 를 추가합니다.</p> </blockquote> <p>sudo /etc/init.d/postgresql restart</p> <p>cmsInitDB</p> </blockquote> <p>Screen을 설치합시다.</p> <blockquote> <p>sudo apt install screen</p> </blockquote> <p>어드민 계정을 생성하고 AdminWebServer를 실행합시다. 아이디는 admin, 비밀번호는 rootroot라고 합시다.</p> <blockquote> <p>cmsAddAdmin -p rootroot admin</p> <p>screen -S AWS</p> <p>cmsAdminWebServer</p> <p>ctrl+A D</p> </blockquote> <p>LogService를 실행합시다.</p> <blockquote> <p>screen -S Log</p> <p>cmsLogService</p> <p>ctrl+A D</p> </blockquote> <p>Admin Web에서 대회를 하나 만들고 대회를 실행합시다.</p> <blockquote> <p>screen -S Resource</p> <p>cmsResourceService -a 1</p> <p>ctrl+A D</p> </blockquote> <h4 id="스코어보드-서버-설정">스코어보드 서버 설정</h4> <p>메인 서버를 세팅하면서 CMS 소스 코드를 스코어보드 서버에 전송했습니다.<br /> 필요한 패키지를 설치하고 config 파일을 적용합시다.</p> <blockquote> <p>cd cms</p> <p>sudo apt install build-essential openjdk-8-jdk-headless fp-compiler postgresql postgresql-client python3.6 cppreference-doc-en-html cgroup-lite libcap-dev zip</p> <p>sudo apt install python3.6-dev libpq-dev libcups2-dev libyaml-dev libffi-dev python3-pip</p> <p>sudo pip3 install -r requirements.txt</p> <p>sudo python3 setup.py install</p> <p>sudo python3 ./prerequisites.py –as-root install</p> </blockquote> <p>스코어보드 서버를 실행합시다.</p> <blockquote> <p>screen -S Ranking</p> <p>cmsRankingWebServer</p> <p>ctrl+A D</p> </blockquote> <h4 id="채점-서버worker-설정">채점 서버(Worker) 설정</h4> <p>메인 서버를 세팅하면서 CMS 소스 코드를 스코어보드 서버에 전송했습니다.<br /> 필요한 패키지를 설치하고 config 파일을 적용합시다.</p> <blockquote> <p>cd cms</p> <p>sudo apt install build-essential openjdk-8-jdk-headless fp-compiler postgresql postgresql-client python3.6 cppreference-doc-en-html cgroup-lite libcap-dev zip</p> <p>sudo apt install python3.6-dev libpq-dev libcups2-dev libyaml-dev libffi-dev python3-pip</p> <p>sudo pip3 install -r requirements.txt</p> <p>sudo python3 setup.py install</p> <p>sudo python3 ./prerequisites.py –as-root install</p> </blockquote> <p>Worker를 켭시다.</p> <blockquote> <p>screen -S Resource</p> <p>cmsWorker</p> <p>ctrl+A D</p> </blockquote> <h4 id="유저-추가">유저 추가</h4> <p>Admin Web을 이용해 testuser를 하나 추가합시다.</p> <h4 id="batch-문제-업로드">Batch 문제 업로드</h4> <p>Admin Web 메인 페이지 좌측 탭에서 <code class="language-plaintext highlighter-rouge">Tasks &gt; create new task...</code>를 눌러서 <code class="language-plaintext highlighter-rouge">a-plus-b</code>라는 문제를 하나 만듭시다.</p> <ul> <li>Statements는 문제 지문을 의미합니다. 한글 디스크립션의 경우, Language code는 <code class="language-plaintext highlighter-rouge">ko-kr</code>로 지정하면 됩니다.</li> <li>Feedback level은 채점 결과를 참가자에게 얼마나 자세하게 알려줄지 결정합니다. 직접 설정해서 확인해보시기 바랍니다.</li> <li>Score options는 위에서 설명한 점수 산출 방식입니다.</li> <li>Task type은 Batch, Compilation은 self-sufficient, Output evaluation은 white diff로 합시다.</li> <li>Test cases는 채점 데이터를 의미합니다. <code class="language-plaintext highlighter-rouge">01.in/01.out, 02.in/02.out</code>처럼 입출력 파일 쌍을 맞춰서 업로드하시면 됩니다.</li> <li>Score type settings은 <a href="https://cms.readthedocs.io/en/v1.4/Score%20types.html">공식 문서</a>를 참고해주세요.</li> </ul> <p>테스트케이스를 적당히 올리면 문제가 완성됩니다.<br /> 위에서 미리 만들어준 대회에 들어간 뒤, Tasks에 <code class="language-plaintext highlighter-rouge">a-plus-b</code>문제를 추가하면 대회에서 문제를 풀어볼 수 있습니다. 채점이 잘 되는지, 문제를 푼 뒤 스코어보드에 잘 반영되는지 확인해보시면 이번 글은 마무리가 됩니다.</p>JusticeHui앞으로 2-3개의 글을 통해 CMS로 대회를 개최하는 방법을 소개하려고 합니다. 이번 글에서는 CMS의 구조를 간단하게 소개하고, CMS를 이용해 대회를 만들고 간단한 Batch 문제를 업로드하는 방법을 소개합니다. SPJ/Grader/Interactive 문제를 업로드하는 방법과 더 정교하게 채점환경을 구축하는 것은 다음 글에서 소개하도록 하겠습니다.2021 KOI 1차대회 고등부 문제 풀이2021-05-17T03:15:00+00:002021-05-17T03:15:00+00:00https://justicehui.github.io/koi/2021/05/17/koi-2021-1<h3 id="총평-및-문제-감상">총평 및 문제 감상</h3> <p>이제 대학생이라 KOI에 참가하지 못하지만, 그래도 제가 한동안 정말 열심히 준비했던 대회인 만큼 풀이는 지속적으로 작성할 생각입니다.</p> <p>작년에 비해 1교시 난이도는 상승한 것 같습니다. 11번까지는 예년보다 크게 어렵지 않지만, 비버 챌린지 난이도가 꽤 많이 상승한 것 같습니다. Nim Game(혹은 Sprague-Grundy Theorem), Burnside’s Lemma, Slope Trick처럼 어려운 개념을 활용하는 문제가 작년보다 증가했습니다. 특히 작년에는 간단한 Nim Game만 출제되었지만 올해는 Sprague-Grundy Number가 직접적으로 출제되었다는 점이 인상적입니다. Nim Game이 2년 연속으로 나왔다는 점에 주목해야 할 것 같습니다.</p> <p>1교시 8/9번처럼 과거 지역 예선(2017년 이전 대회)에서 자주 나왔던 유형의 문제들도 조금씩 보입니다. 2017년 이전 지역 예선 문제를 구해서 공부하는 것도 KOI 1차 대회를 준비하는데 도움이 될 것 같습니다. 1교시 12번 문제처럼 일명 “노가다 문제”라고 부르는 문제들을 어떻게 처리할지 대회 전략을 짜는 것도 중요해 보입니다. (저는 일단 넘어가고 남는 시간에 시도합니다.)</p> <p>비버챌린지 유형의 문제가 특히 인상적입니다. 2019/2020년과 다르게 비버 챌린지에도 서브태스크가 적용되었습니다.<br />“정답이 존재한다” 또는 “이 전략이 최적이다”를 증명할 수 있는 풀이(정해)와 대회 중에 빠르게 풀 수 있는 속칭 야매 풀이가 많이 다른 문제가 몇 개 있습니다. 야매 풀이를 잘 찾기 위해서는 많은 문제를 풀어봐야 합니다. 개인적으로 비버챌린지 기출로 대비하는 것보다는 온라인 저지 사이트에서 다양한 문제를 많이 풀어보는 것을 추천합니다. 비버 챌린지 유형이라고는 하지만, 실제로 비버 챌린지에 출제되는 문제보다 알고리즘 지식과 사고력을 훨씬 많이 요구하기 때문에 온라인 저지 사이트에서 다양한 문제를 풀어보는 것이 좋을 것입니다.</p> <p>2교시 실기 문제 난이도는 2019년보다는 확실히 쉽고, 2020년과 비교했을 때도 2번을 제외하면 많이 쉬워진 느낌입니다. 2019/2020 문제와는 다르게 올해 2/3번 문제에서 Codeforces 느낌이 많이 나네요. 이 점도 다음 대회를 준비할 때 고려하면 좋을 것 같습니다.</p> <p>2교시 실기 문제는 아직 검증되지 않은 코드입니다. 풀이에서 언급한 로직을 구현하긴 했지만, 코딩 미스로 인해 틀렸을 가능성이 있는 코드이니 양해 부탁드립니다. 온라인 저지에 문제가 올라오면 채점을 받은 뒤 검증된 코드로 수정할 예정입니다.</p> <h3 id="문제-유형">문제 유형</h3> <table> <thead> <tr> <th>문제</th> <th>유형</th> <th>문제</th> <th>유형</th> <th>문제</th> <th>유형</th> <th>문제</th> <th>유형</th> </tr> </thead> <tbody> <tr> <td>1번</td> <td>경우의 수</td> <td>2번</td> <td>DP</td> <td>3번</td> <td>경우의 수</td> <td>4번</td> <td>경우의 수</td> </tr> <tr> <td>5번</td> <td>Nim Game</td> <td>6번</td> <td>경우의 수<br />Burnside’s Lemma</td> <td>7번</td> <td>함수/정수론</td> <td>8번</td> <td>ad-hoc</td> </tr> <tr> <td>9번</td> <td>ad-hoc</td> <td>10번</td> <td>ad-hoc</td> <td>11번</td> <td>DP</td> <td>12번</td> <td>DP</td> </tr> <tr> <td>13번</td> <td>DP/휴리스틱</td> <td>14번</td> <td>시뮬레이션</td> <td>15번</td> <td>위상정렬</td> <td>16번</td> <td>BFS</td> </tr> <tr> <td>17번</td> <td>DP/Slope Trick</td> <td>18번</td> <td>Sprague-Grundy</td> <td>19번</td> <td>휴리스틱</td> <td>20번</td> <td>ad-hoc</td> </tr> <tr> <td>1번</td> <td>수학/이분탐색</td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> <tr> <td>2번</td> <td>수학/그리디</td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> <tr> <td>3번</td> <td>투포인터/누적합</td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> </tbody> </table> <h3 id="1-1-상금-배분-8점">1-1. 상금 배분 (8점)</h3> <p>A가 $a$번, B가 $b$번 이기는 경우의 수는 $f(a, b) = \begin{cases} {a+b-3 \choose b} &amp; a = 4 \ {a+b-3 \choose b-1} &amp; a \geq 2, b = 4 \end{cases}$로 계산할 수 있습니다. 또한 각 경우의 수가 발생하는 확률은 $p(a, b) = 1 / 2^{a+b-2}$로 계산할 수 있습니다.</p> <p>(A가 이기는 횟수, B가 이기는 횟수)로 가능한 모든 순서쌍과 경우의 수, 확률을 나열해봅시다.</p> <table> <thead> <tr> <th> </th> <th>경우의 수</th> <th>확률</th> </tr> </thead> <tbody> <tr> <td>(4, 0)</td> <td>1C0 = 1</td> <td>1 * 1/4 = 4/16</td> </tr> <tr> <td>(4, 1)</td> <td>2C1 = 2</td> <td>2 * 1/8 = 4/16</td> </tr> <tr> <td>(4, 2)</td> <td>3C2 = 3</td> <td>3 * 1/16 = 3/16</td> </tr> <tr> <td>(4, 3)</td> <td>4C3 = 4</td> <td>4 * 1/32 = 2/16</td> </tr> <tr> <td>(2, 4)</td> <td>3C3 = 1</td> <td>1 * 1/16 = 1/16</td> </tr> <tr> <td>(3, 4)</td> <td>4C3 = 4</td> <td>4 * 1/32 = 2/16</td> </tr> </tbody> </table> <p>A가 4번 이길 확률은 $13/16$이고, B가 4번 이길 확률은 $3/16$입니다. 그러므로 정답은 13억원이 됩니다.</p> <h3 id="1-2-구슬-경로의-수-8점">1-2. 구슬 경로의 수 (8점)</h3> <p>손으로 DP를 계산하면 됩니다.</p> <p><img src="/img/koi-2021-1-2.PNG" alt="" /></p> <p>정답은 35입니다.</p> <h3 id="1-3-동전과-확률-8점">1-3. 동전과 확률 (8점)</h3> <p>동전을 2개 뒤집는 경우의 수는 ${10 \choose 2} = \frac{90}{2}$이고, 뒷면이 모두 A인 경우의 수는 ${x \choose 2} = \frac{x^2-x}{2}$입니다.<br />$\frac{x^2-x}{90} \leq \frac{4}{10}, x(x-1) \leq 36$을 만족하는 가장 큰 자연수 $x$는 6입니다.</p> <h3 id="1-4-발표-순서-8점">1-4. 발표 순서 (8점)</h3> <p>문자열의 Prefix를 고정시킨 뒤, 그 Prefix로 시작하는 문자열의 개수를 구하면 쉽게 해결할 수 있습니다.</p> <ul> <li><code class="language-plaintext highlighter-rouge">Axxxxx</code> : 120가지 / 누적 120</li> <li><code class="language-plaintext highlighter-rouge">Bxxxxx</code> : 120가지 / 누적 240</li> <li><code class="language-plaintext highlighter-rouge">CAxxxx</code> : 24가지 / 누적 264</li> <li><code class="language-plaintext highlighter-rouge">CBADEF</code> : 1가지 / 누적 265</li> </ul> <p>정답은 265입니다.</p> <h3 id="1-5-돌-무더기-게임-9점">1-5. 돌 무더기 게임 (9점)</h3> <p>전형적인 Nim Game입니다. 각 덩어리에 있는 돌의 개수를 xor했을 때 0이라면 항상 후공이 이기는 전략이 존재하고, 0이 아니라면 항상 선공이 이기는 전략이 존재합니다.<br />1, 2, 3을 xor하면 0이기 때문에 항상 B가 이기는 전략이 존재합니다.</p> <h3 id="1-6-직소-퍼즐-9점">1-6. 직소 퍼즐 (9점)</h3> <p>전형적인 Burnside’s Lemma 문제입니다. 작년에 Algoshitpo 팀 블로그에서 <a href="https://algoshitpo.github.io/2020/02/09/burnside/">Burnside’s Lemma 튜토리얼</a>을 작성했으니 참고하시면 됩니다.</p> <p>$c(k) = 2^{\text{gcd}(k, 6)}$이라고 하면 정답은 $\displaystyle \frac{1}{6} \sum_{k=1}^{6} c(k) = 84/6 = 14$입니다.</p> <h3 id="1-7-삼각형-위의-격자점-9점">1-7. 삼각형 위의 격자점 (9점)</h3> <p>삼각형의 각 변을 선분으로 생각합시다. 선분의 한쪽 끝점을 $(0, 0)$으로 옮기면 $y = \frac{b}{a}x, (0 &lt; x &lt; k)$와 같이 $x$좌표 범위가 제한된 일차함수라고 생각할 수 있습니다. $x$가 정수일 때 $bx$가 $a$의 배수가 되는 경우의 수를 세면 됩니다. 꼭짓점은 따로 생각하는 것이 편합니다.</p> <ul> <li>$\overline{AB} : y = \frac{29}{155}x, (0 &lt; x &lt; 155)$ : 0개</li> <li>$\overline{BC} : y = \frac{5}{7}x, (0 &lt; x &lt; 210)$ : 29개</li> <li>$\overline{CA} : y = \frac{11}{5}x, (0 &lt; x &lt; 55)$ : 10개</li> <li>꼭짓점 : 3개</li> </ul> <p>정답은 42개입니다.</p> <h3 id="1-8-숫자-추측-9점">1-8. 숫자 추측 (9점)</h3> <p>일단 가능한 경우의 수를 모두 나열해봅시다.</p> <ol> <li>(1, 1) : 합 2 곱 1</li> <li>(1, 2) : 합 3 곱 2</li> <li>(1, 3) : 합 4 곱 3</li> <li>(1, 4) : 합 5 곱 4</li> <li>(2, 2) : 합 4 곱 4</li> <li>(2, 3) : 합 5 곱 6</li> <li>(2, 4) : 합 6 곱 8</li> <li>(3, 3) : 합 6 곱 9</li> <li>(3, 4) : 합 7 곱 12</li> <li>(4, 4) : 합 8 곱 16</li> </ol> <p><code class="language-plaintext highlighter-rouge">다래</code>는 두 수 $a, b$의 곱을 알고 있는 사람입니다. $ab$를 알고 있을 때 $a, b$의 값을 모른다면 $ab$는 4입니다.<br /><code class="language-plaintext highlighter-rouge">나은</code>은 두 수 $a, b$의 합을 알고 있는 사람입니다. $a+b$를 알고 있을 때 $a, b$의 값을 모른다면 $a+b$는 4 5 6 중 하나입니다.</p> <p><code class="language-plaintext highlighter-rouge">다래</code>가 <code class="language-plaintext highlighter-rouge">나은</code>에게 $ab$가 4라는 정보를 제공했기 때문에, $ab$와 $a+b$를 모두 알고 있는 <code class="language-plaintext highlighter-rouge">나은</code>은 $a, b$의 값을 알 수 있습니다. 하지만 <code class="language-plaintext highlighter-rouge">다래</code>는 $a+b$가 4 5 6 중 하나라는 정보를 알고 있어도 (1, 4), (2, 2) 중 어떤 것이 답인지 알지 못합니다.</p> <p><code class="language-plaintext highlighter-rouge">다래</code>가 $a \neq b$라는 정보를 얻고 나면 $a, b$가 각각 1, 4라는 것을 알게 됩니다. 정답은 17입니다.</p> <h3 id="1-9-항아리-10점">1-9. 항아리 (10점)</h3> <p>각 행동 별로 $b, w$가 어떻게 변화하는지 생각해봅시다.</p> <ol> <li>검은 돌 2개를 꺼낸 경우 : $(b, w) \rightarrow (b-1, w)$</li> <li>흰 돌 2개를 꺼낸 경우 : $(b, w) \rightarrow (b+1, w-2)$</li> <li>1개씩 꺼낸 경우 : $(b, w) \rightarrow (b-1, w)$</li> </ol> <p>문제 지문에서는 무작위로 돌을 꺼낸다고 하지만, 결과가 한 개로 정해져 있기 때문에 <strong>원하는 순서대로</strong> 돌을 꺼내도 무방합니다. (2)를 이용해 흰색 돌을 최대한 많이 없앤 뒤, (1)과 (3)을 이용해 검은색 돌을 모두 없애는 전략을 사용할 것입니다.</p> <p>만약 $w$가 짝수라면, (2)를 이용해 흰 돌을 모두 없앨 수 있습니다. 그 다음 (1)을 이용해 검은 돌을 한 개만 남길 수 있습니다.<br />만약 $w$가 홀수라면, (2)를 이용해 흰 돌을 한 개만 남길 수 있습니다. 그 다음 (3)을 이용해 검은 돌을 모두 없앨 수 있습니다.</p> <p>$\text{jug}(10, 34), \text{jug}(45, 5), \text{jug}(100, 111)$은 각각 B, W, W입니다.</p> <h3 id="1-10-중심-노드-찾기-10점">1-10. 중심 노드 찾기 (10점)</h3> <p><a href="https://www.geeksforgeeks.org/the-celebrity-problem/">The Celebrity Problem</a>으로 잘 알려진 문제입니다.</p> <p>2명의 사람 $a, b$를 임의로 선택해서 $\text{query}(a, b)$를 호출합시다. 만약 반환값이 <code class="language-plaintext highlighter-rouge">yes</code>라면 $a$는 중심 노드가 될 수 없습니다. 만약 반환값이 <code class="language-plaintext highlighter-rouge">no</code>라면 $b$는 중심 노드가 될 수 없습니다.</p> <p><strong>(상한)</strong> 쿼리 1번으로 후보 해를 최소 1개 이상 제거할 수 있으므로 최악의 경우 $n-1$번의 쿼리를 통해 중심 노드를 찾을 수 있습니다.<br /><strong>(하한)</strong> 쿼리 1번으로 최대 1개의 후보 해를 제거할 수 있기 때문에 하한도 $n-1$이 됩니다.</p> <h3 id="1-11-두-번-이상-지나는-경로-찾기-10점">1-11. 두 번 이상 지나는 경로 찾기 (10점)</h3> <p>여사건을 생각합시다. 전체 경우의 수에서 0번 / 1번 지나는 경로의 개수를 제거하면 됩니다.</p> <p><img src="/img/koi-2021-1-11.PNG" alt="" /></p> <p>전체 경우의 수는 64가지입니다. 0번 지나는 경로는 존재하지 않고, 1번 지나는 경로는 11개 존재합니다.<br />구체적으로,</p> <ul> <li>빨간색 점만 지나는 경로 : 0개</li> <li>노란색 점만 지나는 경로 : 1개</li> <li>초록색 점만 지나는 경로 : 6개 (출발 → 초록 2가지, 초록 → 도착 3가지)</li> <li>파란색 점만 지나는 경로 : 1개</li> <li>보라색 점만 지나는 경로 : 3개 (출발 → 보라 1가지, 보라 → 도착 3가지)</li> </ul> <p>정답은 64 - 11 = 53입니다.</p> <h3 id="1-12-사각형-세기-10점">1-12. 사각형 세기 (10점)</h3> <p>정답은 30이니 다른 문제를 모두 풀고 남는 시간 동안 열심히 찾으면 됩니다.</p> <h3 id="1-13-첫-월급-9점">1-13. 첫 월급 (9점)</h3> <p>$D[i] := $ 선물 상자 $i$개를 구매하는 최소 비용이라고 정의하면 점화식은 $D[i] = \min(D[i-1]+175, D[i-3]+400, D[i-5]+700)$이 됩니다. 점화식을 계산하고 역추적을 하면 1, 3, 3, 3개 구매하는 것이 최적임을 알 수 있습니다.</p> <p>또는 선물 상자를 1, 3, 5개 구매할 때 개당 175, 133.33, 140원이라는 것을 이용해 효율이 좋은 상품을 많이 구매하는 휴리스틱을 사용해도 됩니다.</p> <h3 id="1-14-하노이의-탑-9점">1-14. 하노이의 탑 (9점)</h3> <p>횟수를 최소화할 필요는 없으므로 자유롭게 하면 됩니다.</p> <h3 id="1-15-2등을-찾아라-9점">1-15. 2등을 찾아라! (9점)</h3> <p>위상 정렬을 생각해봅시다.<br />어떤 정점 $v$가 2등이 될 수 있다는 것은, 위상 정렬을 했을 때 $v$가 2번째로 오는 경우가 존재하는 것을 의미합니다.</p> <p>1일차에는 모든 정점이 2등이 될 수 있습니다.</p> <ul> <li>1/2/8은 각각 5/3/4 바로 다음에 오면 2등이 됩니다.</li> <li>나머지 다른 정점들은 임의의 in-degree가 0인 정점 다음에 나오면 2등이 될 수 있습니다.</li> </ul> <p>2일차에는 1, 3, 4, 5, 6이 2등이 될 수 있습니다.</p> <ul> <li>7은 3, 2가 항상 먼저 나와야 하기 때문에 2등이 될 수 없습니다.</li> <li>2는 3, 4보다 나중에 나와야 하기 때문에 2등이 될 수 없습니다.</li> <li>8은 3, 5보다 나중에 나와야 하기 때문에 2등이 될 수 없습니다.</li> <li>1/6은 3 다음에 오면 2등이 됩니다.</li> <li>3/4/5는 임의의 in-degree가 0인 정점 다음에 나오면 2등이 될 수 있습니다.</li> </ul> <p>3일차에는 3, 5만 2등이 될 수 있습니다.</p> <ul> <li>4는 무조건 1등입니다.</li> <li>1/6은 4, 3보다 나중에 나와야 하기 때문에 2등이 될 수 없습니다.</li> <li>3/5는 4 다음에 오면 2등이 됩니다.</li> </ul> <p>4일차에는 3만 2등이 될 수 있습니다.</p> <ul> <li>5는 4, 3보다 나중에 나와야 하기 때문에 2등이 될 수 없습니다.</li> <li>3은 4 다음에 오면 2등이 됩니다.</li> </ul> <h3 id="1-16-천사와-악마-12점">1-16. 천사와 악마 (12점)</h3> <p>손으로 BFS를 직접 시뮬레이션 한다고 생각합시다.<br />천사가 살고 있는 정점과 7 이상 떨어져 있는 정점을 모두 제거합시다. 빨간색 체크가 되어 있는 정점과 7 이상 떨어져 있는 정점은 빨간색으로, 초록색 체크가 되어 있는 정점과 7 이상 떨어져 있는 정점은 초록색으로 색칠했습니다.<br />마찬가지로 악마가 살고 있는 정점과 2 이하로 떨어져 있는 정점을 모두 제거합시다. 하늘색, 파란색, 보라색으로 표시했습니다.</p> <p><img src="/img/koi-2021-1-16.PNG" alt="" /></p> <p>색칠되지 않은 정점이 정답입니다.</p> <h3 id="1-17-단조증가-수열-12점">1-17. 단조증가 수열 (12점)</h3> <p>$D(i, j) := $ $A_1, A_2, \cdots , A_i$를 단조 증가 수열로 만들고, $A_i = j$가 되도록 하는 최소 횟수라고 정의합시다. 수가 커질수록 +를 눌러야 하는 횟수가 크게 증가하므로 $j$는 14 이하라고 생각해도 충분합니다.</p> <p>점화식은 $D(i, j) = \min(D(i-1, j-1), D(i-1, j-2), \cdots , D(i-1, 1)) + \vert A_i - j \vert$가 됩니다. $8 \cdot 14$ 크기의 DP Table을 직접 채우고 최적해를 역추적하면 문제를 풀 수 있습니다.</p> <p><img src="/img/koi-2021-1-17.png" alt="" /></p> <p>컴퓨터를 이용해서 이런 점화식을 계산할 때 <a href="https://jwvg0425.github.io/ps/slope_trick.html">Slope Trick</a>을 이용하면 $O(NX)$를 $O(N \log N)$으로 최적화할 수 있습니다. 관심 있는 분들은 한 번 공부해보세요. ($N$: 원소 개수, $X$: 수 범위)</p> <h3 id="1-18-삼각형-게임-13점">1-18. 삼각형 게임 (13점)</h3> <p>점이 $n$개 있을 때 선분을 하나 그리면 점이 각각 $a$개 있는 게임과 $n-a-2$개 있는 게임으로 나뉘게 됩니다. 자신이 선분을 그리는 것으로 인해 모든 게임을 <strong>점이 1개인 게임</strong>으로 만들 수 있다면 승리할 수 있습니다.</p> <p>$G(1) = 0$이므로 Sprague-Grundy Theorem을 이용하는 문제라는 것은 쉽게 알 수 있습니다. Grundy Number를 잘 구해봅시다.</p> <ul> <li>$G(0) = 0$</li> <li>$G(1) = 0$</li> <li>$G(2) = 1 = \text{mex}(G(0) \bigoplus G(0)) = \text{mex}(0)$</li> <li>$G(3) = 1 = \text{mex}(G(0) \bigoplus G(1)) = \text{mex}(0)$</li> <li>$G(4) = 2 = \text{mex}(G(0) \bigoplus G(2), G(1) \bigoplus G(1)) = \text{mex}(1, 0)$</li> <li>$G(5) = 0 = \text{mex}(G(0) \bigoplus G(3), G(1) \bigoplus G(2)) = \text{mex}(1, 1)$</li> <li>$G(6) = 3 = \text{mex}(G(0) \bigoplus G(4), G(1) \bigoplus G(3), G(2) \bigoplus G(2)) = \text{mex}(2, 1, 0)$</li> <li>$G(7) = 1 = \text{mex}(G(0) \bigoplus G(5), G(1) \bigoplus G(4), G(2) \bigoplus G(3)) = \text{mex}(0, 2, 0)$</li> <li>$G(8) = 1 = \text{mex}(G(0) \bigoplus G(6), G(1) \bigoplus G(5), G(2) \bigoplus G(4), G(3) \bigoplus G(3)) = \text{mex}(3, 0, 3, 0)$</li> <li>$G(9) = 0 = \text{mex}(G(0) \bigoplus G(7), G(1) \bigoplus G(6), G(2) \bigoplus G(5), G(3) \bigoplus G(4)) = \text{mex}(1, 3, 1, 3)$</li> <li>$G(10) = 3 = \text{mex}(G(0) \bigoplus G(8), G(1) \bigoplus G(7), G(2) \bigoplus G(6), G(3) \bigoplus G(5), G(4) \bigoplus G(4)) = \text{mex}(1, 1, 2, 1, 0)$</li> <li>$G(11) = 3 = \text{mex}(G(0) \bigoplus G(9), G(1) \bigoplus G(8), G(2) \bigoplus G(7), G(3) \bigoplus G(6), G(4) \bigoplus G(5)) = \text{mex}(0, 1, 0, 2, 2)$</li> <li>$G(12) = 2 = \text{mex}(G(0) \bigoplus G(10), G(1) \bigoplus G(9), G(2) \bigoplus G(8), G(3) \bigoplus G(7), G(4) \bigoplus G(6), G(5) \bigoplus G(5)) = \text{mex}(3, 0, 0, 0, 1, 0)$</li> <li>$G(13) = 2 = \text{mex}(G(0) \bigoplus G(11), G(1) \bigoplus G(10), G(2) \bigoplus G(9), G(3) \bigoplus G(8), G(4) \bigoplus G(7), G(5) \bigoplus G(6)) = \text{mex}(3, 3, 1, 0, 3, 3)$</li> </ul> <p>$G(13) \neq 0$이므로 플레이어가 항상 승리하는 필승법이 존재합니다. 게임 판의 상태(모든 게임의 Grundy Number를 xor한 결과)가 0이 되도록 만들어주면 됩니다.<br />첫 번째 턴에 게임을 (3, 8)로 쪼개면 됩니다. ($G(3) \bigoplus G(8) = 1 \bigoplus 1 = 0$)</p> <h3 id="1-19-팀-구성-14점">1-19. 팀 구성 (14점)</h3> <p>문제를 보자마자 정말 막막하다는 생각이 듭니다. 사각형 세기와 더불어 가장 마지막에 푸는 것을 추천합니다.<br />정답을 구하는 과정을 소개하면 너무 길어지기 때문에, 시도해볼만한 전략만 몇 가지 소개하고 넘어가겠습니다. 정답은 <a href="https://koi.or.kr/assets/koi/2021/1/solutions/h1-answers.pdf">KOI 공식 답지</a>의 29-32페이지를 참고하세요.</p> <p>탐색해야 할 후보가 너무 많기 때문에, 적당한 전략을 활용해 탐색 범위를 줄이는 것이 중요합니다.</p> <ul> <li>인접한 0 이상의 수들은 한 그룹으로 묶을 수 있습니다.</li> <li>리프 노드가 음수라면 그 리프 노드를 제거해도 됩니다. (ex. 중앙 상단에 있는 -1)</li> <li>음수를 뚫고 들어갔을 때 이득을 볼 수 있다면 뚫고 들어갑니다. (ex. 우측 하단에서 -1을 뚫고 들어가면 1, 1, 2를 먹을 수 있습니다.)</li> <li>리프 노드부터 시작해 적당한 양수 서브 트리를 묶으면 편합니다. (ex. 우측 상단에 있는 5, 1, -5)</li> </ul> <h3 id="1-20-2행-정렬-14점">1-20. 2행 정렬 (14점)</h3> <p>적절히 swap해서 아래처럼 만든 다음, $(1, 1), (2, 2), \cdots , (15, 15)$를 바꿔주면 됩니다.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 </code></pre></div></div> <h3 id="2-1-야구-시즌-100점">2-1. 야구 시즌 (100점)</h3> <p>같은 지역 리그에 있는 팀끼리 $A$번, 다른 지역 리그에 있는 팀끼리 $B$번 경기를 하면 총 $f(A, B) = A \cdot N \cdot \frac{M \cdot (M-1)}{2} + B \cdot \frac{NM \cdot (NM-M)}{2} = $ $ANM(M-1)/2 + BNM^2(N-1)/2$번 경기를 진행합니다.</p> <p>$A = kB$라고 두면, $f(kB, B) \leq D$를 만족하는 가장 큰 자연수 $B$를 찾는 문제가 되고, 변수가 하나이므로 이분 탐색(파라메트릭 서치)을 이용해 $O(\log D)$만에 정답을 구할 수 있습니다.</p> <p>$KBNM(M-1)/2 + BNM^2(N-1)/2 \leq D$를 잘 정리해서 $B \leq \frac{2D}{NM(K(M-1)+M(N-1))}$로 바꾸면 $O(1)$에 계산할 수도 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="k">using</span> <span class="n">ll</span> <span class="o">=</span> <span class="kt">long</span> <span class="kt">long</span><span class="p">;</span> <span class="n">ll</span> <span class="n">N</span><span class="p">,</span> <span class="n">M</span><span class="p">,</span> <span class="n">K</span><span class="p">,</span> <span class="n">D</span><span class="p">;</span> <span class="n">ll</span> <span class="nf">Check</span><span class="p">(</span><span class="n">ll</span> <span class="n">B</span><span class="p">){</span> <span class="n">ll</span> <span class="n">A</span> <span class="o">=</span> <span class="n">K</span> <span class="o">*</span> <span class="n">B</span><span class="p">;</span> <span class="n">ll</span> <span class="n">t1</span> <span class="o">=</span> <span class="n">M</span> <span class="o">*</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="o">/</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">A</span> <span class="o">*</span> <span class="n">N</span><span class="p">;</span> <span class="n">ll</span> <span class="n">t2</span> <span class="o">=</span> <span class="n">N</span><span class="o">*</span><span class="n">M</span> <span class="o">*</span> <span class="p">(</span><span class="n">N</span><span class="o">*</span><span class="n">M</span> <span class="o">-</span> <span class="n">M</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">B</span><span class="p">;</span> <span class="k">return</span> <span class="n">t1</span> <span class="o">+</span> <span class="n">t2</span><span class="p">;</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">Solve</span><span class="p">(){</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span> <span class="o">&gt;&gt;</span> <span class="n">M</span> <span class="o">&gt;&gt;</span> <span class="n">K</span> <span class="o">&gt;&gt;</span> <span class="n">D</span><span class="p">;</span> <span class="n">ll</span> <span class="n">l</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span> <span class="o">=</span> <span class="mf">1e9</span><span class="p">;</span> <span class="k">while</span><span class="p">(</span><span class="n">l</span> <span class="o">&lt;</span> <span class="n">r</span><span class="p">){</span> <span class="n">ll</span> <span class="n">m</span> <span class="o">=</span> <span class="n">l</span> <span class="o">+</span> <span class="n">r</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">&gt;&gt;</span> <span class="mi">1</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">m</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="n">D</span><span class="p">)</span> <span class="n">l</span> <span class="o">=</span> <span class="n">m</span><span class="p">;</span> <span class="k">else</span> <span class="n">r</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">if</span><span class="p">(</span><span class="n">ll</span> <span class="n">res</span><span class="o">=</span><span class="n">Check</span><span class="p">(</span><span class="n">l</span><span class="p">);</span> <span class="n">res</span> <span class="o">&lt;=</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">&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="s">"-1</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="kt">int</span> <span class="n">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">while</span><span class="p">(</span><span class="n">T</span><span class="o">--</span><span class="p">)</span> <span class="n">Solve</span><span class="p">();</span> <span class="p">}</span> </code></pre></div></div> <h3 id="2-2-초직사각형-100점">2-2. 초직사각형 (100점)</h3> <p>주어지는 카드의 $T_i$가 모두 <code class="language-plaintext highlighter-rouge">A</code>라고 가정해봅시다. $U_i$가 큰 것부터 사용하는 것이 그리디가 성립한다는 것을 직관적으로 알 수 있습니다. 이때 사용한 카드들의 $U_i$를 $U_1 \geq U_2 \geq \cdots \geq U_K$이라고 하면, $U_i$를 사용했을 때 부피의 증가율이 $\frac{A_0 + \sum_{j=1}^{i} U_j}{A_0 +\sum_{j=1}^{i-1} U_j}$이라는 것을 알 수 있습니다.</p> <p>이 풀이를 확장시키면 만점 풀이를 얻을 수 있습니다. 주어진 카드들을 $T_i$에 따라 분류하면, 각 그룹 별로 증가율을 독립적으로 계산할 수 있습니다. 그러므로 각 그룹 별로 $U_i$에 대해 내림차순으로 정렬하고 전부 모아서 증가율이 큰 카드부터 사용하면 됩니다.<br />분수의 분자/분모가 각각 $2 \cdot 10^{11}$ 정도까지 커질 수 있으므로, 분수를 비교할 때 <code class="language-plaintext highlighter-rouge">__int128_t</code>를 사용해야 합니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; #define all(v) v.begin(), v.end() </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">LL</span> <span class="o">=</span> <span class="n">__int128_t</span><span class="p">;</span> <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">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="mi">4</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">S</span><span class="p">[</span><span class="mi">4</span><span class="p">];</span> <span class="k">struct</span> <span class="nc">Card</span><span class="p">{</span> <span class="kt">int</span> <span class="n">id</span><span class="p">,</span> <span class="n">idx</span><span class="p">;</span> <span class="n">Card</span><span class="p">(){}</span> <span class="n">Card</span><span class="p">(</span><span class="kt">int</span> <span class="n">id</span><span class="p">,</span> <span class="kt">int</span> <span class="n">idx</span><span class="p">)</span> <span class="o">:</span> <span class="n">id</span><span class="p">(</span><span class="n">id</span><span class="p">),</span> <span class="n">idx</span><span class="p">(</span><span class="n">idx</span><span class="p">)</span> <span class="p">{}</span> <span class="p">};</span> <span class="kt">bool</span> <span class="k">operator</span> <span class="o">&gt;</span> <span class="p">(</span><span class="k">const</span> <span class="n">Card</span> <span class="o">&amp;</span><span class="n">a</span><span class="p">,</span> <span class="k">const</span> <span class="n">Card</span> <span class="o">&amp;</span><span class="n">b</span><span class="p">){</span> <span class="n">LL</span> <span class="n">a1</span> <span class="o">=</span> <span class="n">S</span><span class="p">[</span><span class="n">a</span><span class="p">.</span><span class="n">id</span><span class="p">][</span><span class="n">a</span><span class="p">.</span><span class="n">idx</span><span class="p">],</span> <span class="n">a2</span> <span class="o">=</span> <span class="n">S</span><span class="p">[</span><span class="n">a</span><span class="p">.</span><span class="n">id</span><span class="p">][</span><span class="n">a</span><span class="p">.</span><span class="n">idx</span><span class="o">-</span><span class="mi">1</span><span class="p">];</span> <span class="n">LL</span> <span class="n">b1</span> <span class="o">=</span> <span class="n">S</span><span class="p">[</span><span class="n">b</span><span class="p">.</span><span class="n">id</span><span class="p">][</span><span class="n">b</span><span class="p">.</span><span class="n">idx</span><span class="p">],</span> <span class="n">b2</span> <span class="o">=</span> <span class="n">S</span><span class="p">[</span><span class="n">b</span><span class="p">.</span><span class="n">id</span><span class="p">][</span><span class="n">b</span><span class="p">.</span><span class="n">idx</span><span class="o">-</span><span class="mi">1</span><span class="p">];</span> <span class="k">return</span> <span class="n">a1</span><span class="o">*</span><span class="n">b2</span> <span class="o">&gt;</span> <span class="n">b1</span><span class="o">*</span><span class="n">a2</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">K</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span><span class="n">t</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">4</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">i</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="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">char</span> <span class="n">T</span><span class="p">;</span> <span class="n">ll</span> <span class="n">U</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">T</span> <span class="o">&gt;&gt;</span> <span class="n">U</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="sc">'A'</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">U</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">i</span><span class="o">&lt;</span><span class="mi">4</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="mi">1</span><span class="o">+</span> <span class="n">all</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">greater</span><span class="o">&lt;&gt;</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">resize</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">size</span><span class="p">());</span> <span class="n">partial_sum</span><span class="p">(</span><span class="n">all</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">S</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="p">}</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">Card</span><span class="o">&gt;</span> <span class="n">cards</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">4</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">V</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">size</span><span class="p">();</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="n">cards</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">);</span> <span class="p">}</span> <span class="n">sort</span><span class="p">(</span><span class="n">all</span><span class="p">(</span><span class="n">cards</span><span class="p">),</span> <span class="n">greater</span><span class="o">&lt;&gt;</span><span class="p">());</span> <span class="n">cards</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">K</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">id</span><span class="p">,</span><span class="n">idx</span><span class="p">]</span> <span class="o">:</span> <span class="n">cards</span><span class="p">)</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="kt">char</span><span class="p">(</span><span class="sc">'A'</span> <span class="o">+</span> <span class="n">id</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span> <span class="o">&lt;&lt;</span> <span class="n">V</span><span class="p">[</span><span class="n">id</span><span class="p">][</span><span class="n">idx</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="2-3-공통-부분-수열-확장-100점">2-3. 공통 부분 수열 확장 (100점)</h3> <p>어떤 문자열 $S$의 $i$번째 문자부터 $j-1$번째 문자로 구성된 부분 문자열을 $S[i:j]$라고 정의합시다. 반 열린 구간 $[i, j)$라고 생각하면 됩니다.</p> <p>문자열 $W$가 확장 가능하다는 것은 어떤 수 $k(0 \leq k \leq \vert W \vert)$와 문자 $c$가 있어서, $W[0:k] + c + W[k:\vert W\vert]$가 $X, Y$의 공통 부분 수열이 된다는 것을 의미합니다. 이러한 $k, c$가 존재하는지 빠르게 알아내야 합니다.</p> <p>$W$의 접두사(Prefix) $W[0:j]$가 $X$의 접두사 $X[0:i]$의 부분 수열이 되는 가장 작은 $i$을 $\text{PreX}[j]$라고 합시다.<br />$W$의 접미사(Suffix) $W[j:\vert W \vert]$가 $X$의 접미사 $X[i:\vert W \vert]$의 부분 수열이 되는 가장 큰 $i$를 $\text{SufX}[j]$라고 합시다.<br />$\text{PreY}[j], \text{SufY}[j]$도 비슷하게 정의할 수 있습니다.</p> <p>어떤 수 $k$와 어떤 수 $c$에 대해 $W$를 $W[0:k] + c + W[k:\vert W\vert]$로 확장 가능하다는 것은, $X[\text{PreX}[k]:\text{SufX}[k]]$과 $Y[\text{PreY}[k]:\text{SufY}[k]]$가 각각 $c$를 포함하고 있다는 것과 동치입니다.</p> <p>$\text{PreX}, \text{SufX}, \text{PreY}, \text{SufY}$는 투포인터를 이용해 $O(\vert X \vert + \vert Y \vert)$ 시간에 전처리할 수 있습니다. $X[i:j]$에 어떤 문자 $c$가 존재하는지 확인하는 것은 누적합(Prefix Sum)을 이용하면 $O(\vert X \vert)$ 전처리를 통해 $O(1)$ 시간에 확인할 수 있습니다.</p> <p>그러므로 문제를 $O(\vert X \vert + \vert Y \vert)$에 해결할 수 있습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &lt;bits/stdc++.h&gt; #define all(v) v.begin(), v.end() </span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">M</span><span class="p">,</span> <span class="n">K</span><span class="p">;</span> <span class="n">string</span> <span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">W</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">PreX</span><span class="p">,</span> <span class="n">SufX</span><span class="p">,</span> <span class="n">PreY</span><span class="p">,</span> <span class="n">SufY</span><span class="p">;</span> <span class="n">array</span><span class="o">&lt;</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="mi">26</span><span class="o">&gt;</span> <span class="n">PosX</span><span class="p">,</span> <span class="n">PosY</span><span class="p">;</span> <span class="kt">void</span> <span class="nf">Clear</span><span class="p">(){</span> <span class="n">PreX</span><span class="p">.</span><span class="n">clear</span><span class="p">();</span> <span class="n">SufX</span><span class="p">.</span><span class="n">clear</span><span class="p">();</span> <span class="n">PreY</span><span class="p">.</span><span class="n">clear</span><span class="p">();</span> <span class="n">SufY</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">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">26</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">PosX</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">clear</span><span class="p">(),</span> <span class="n">PosY</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">clear</span><span class="p">();</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">Resize</span><span class="p">(){</span> <span class="n">N</span> <span class="o">=</span> <span class="n">X</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">Y</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">K</span> <span class="o">=</span> <span class="n">W</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">PreX</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">K</span><span class="p">);</span> <span class="n">SufX</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">K</span><span class="p">);</span> <span class="n">PreY</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">K</span><span class="p">);</span> <span class="n">SufY</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">K</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">26</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">PosX</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">resize</span><span class="p">(</span><span class="n">N</span><span class="p">),</span> <span class="n">PosY</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">M</span><span class="p">);</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">PreCalc</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="o">&amp;</span><span class="n">Pre</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="o">&amp;</span><span class="n">Suf</span><span class="p">,</span> <span class="n">array</span><span class="o">&lt;</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="mi">26</span><span class="o">&gt;</span> <span class="o">&amp;</span><span class="n">Pos</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">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">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">W</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="n">Pre</span><span class="p">[</span><span class="n">j</span><span class="o">++</span><span class="p">]</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">i</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="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">j</span><span class="o">=</span><span class="n">W</span><span class="p">.</span><span class="n">size</span><span class="p">()</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&gt;=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">--</span><span class="p">)</span> <span class="k">if</span><span class="p">(</span><span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">W</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="n">Suf</span><span class="p">[</span><span class="n">j</span><span class="o">--</span><span class="p">]</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">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">S</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="n">Pos</span><span class="p">[</span><span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">-</span><span class="sc">'a'</span><span class="p">][</span><span class="n">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="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">26</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">partial_sum</span><span class="p">(</span><span class="n">all</span><span class="p">(</span><span class="n">Pos</span><span class="p">[</span><span class="n">i</span><span class="p">]),</span> <span class="n">Pos</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="p">}</span> <span class="kt">bool</span> <span class="nf">Exist</span><span class="p">(</span><span class="kt">int</span> <span class="n">flag</span><span class="p">,</span> <span class="kt">int</span> <span class="n">ch</span><span class="p">,</span> <span class="kt">int</span> <span class="n">s</span><span class="p">,</span> <span class="kt">int</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">&gt;</span> <span class="n">e</span><span class="p">)</span> <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> <span class="n">array</span><span class="o">&lt;</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="mi">26</span><span class="o">&gt;</span> <span class="o">&amp;</span><span class="n">Pos</span> <span class="o">=</span> <span class="n">flag</span> <span class="o">?</span> <span class="n">PosY</span> <span class="o">:</span> <span class="n">PosX</span><span class="p">;</span> <span class="k">return</span> <span class="n">Pos</span><span class="p">[</span><span class="n">ch</span><span class="p">][</span><span class="n">e</span><span class="p">]</span> <span class="o">-</span> <span class="p">(</span><span class="n">s</span> <span class="o">?</span> <span class="n">Pos</span><span class="p">[</span><span class="n">ch</span><span class="p">][</span><span class="n">s</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">:</span> <span class="mi">0</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="kt">bool</span> <span class="nf">Check</span><span class="p">(</span><span class="kt">int</span> <span class="n">s0</span><span class="p">,</span> <span class="kt">int</span> <span class="n">e0</span><span class="p">,</span> <span class="kt">int</span> <span class="n">s1</span><span class="p">,</span> <span class="kt">int</span> <span class="n">e1</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">s0</span> <span class="o">&gt;</span> <span class="n">e0</span> <span class="o">||</span> <span class="n">s1</span> <span class="o">&gt;</span> <span class="n">e1</span><span class="p">)</span> <span class="k">return</span> <span class="nb">false</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">26</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">Exist</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="n">s0</span><span class="p">,</span> <span class="n">e0</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">Exist</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">s1</span><span class="p">,</span> <span class="n">e1</span><span class="p">))</span> <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="nb">false</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">Clear</span><span class="p">();</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">X</span> <span class="o">&gt;&gt;</span> <span class="n">Y</span> <span class="o">&gt;&gt;</span> <span class="n">W</span><span class="p">;</span> <span class="n">Resize</span><span class="p">();</span> <span class="n">PreCalc</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">PreX</span><span class="p">,</span> <span class="n">SufX</span><span class="p">,</span> <span class="n">PosX</span><span class="p">);</span> <span class="n">PreCalc</span><span class="p">(</span><span class="n">Y</span><span class="p">,</span> <span class="n">PreY</span><span class="p">,</span> <span class="n">SufY</span><span class="p">,</span> <span class="n">PosY</span><span class="p">);</span> <span class="kt">int</span> <span class="n">flag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">flag</span> <span class="o">|=</span> <span class="n">Check</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">SufX</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="mi">0</span><span class="p">,</span> <span class="n">SufY</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">+</span><span class="mi">1</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">flag</span> <span class="o">|=</span> <span class="n">Check</span><span class="p">(</span><span class="n">PreX</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">SufX</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="mi">1</span><span class="p">,</span> <span class="n">PreY</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">SufY</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="mi">1</span><span class="p">);</span> <span class="p">}</span> <span class="n">flag</span> <span class="o">|=</span> <span class="n">Check</span><span class="p">(</span><span class="n">PreX</span><span class="p">[</span><span class="n">K</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">+</span><span class="mi">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="n">PreY</span><span class="p">[</span><span class="n">K</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">+</span><span class="mi">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">cout</span> <span class="o">&lt;&lt;</span> <span class="n">flag</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="kt">int</span> <span class="n">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">while</span><span class="p">(</span><span class="n">T</span><span class="o">--</span><span class="p">)</span> <span class="n">Solve</span><span class="p">();</span> <span class="p">}</span> </code></pre></div></div>JusticeHui총평 및 문제 감상백준20062 Seats2021-05-13T16:15:00+00:002021-05-13T16:15:00+00:00https://justicehui.github.io/ioi/2021/05/13/BOJ20062<h3 id="문제-링크">문제 링크</h3> <ul> <li>http://icpc.me/20062</li> </ul> <h3 id="문제-출처">문제 출처</h3> <ul> <li>2018 IOI Day1 2번</li> </ul> <h3 id="사용-알고리즘">사용 알고리즘</h3> <ul> <li>세그먼트 트리</li> </ul> <h3 id="시간복잡도">시간복잡도</h3> <ul> <li>풀이 참조</li> </ul> <h3 id="풀이">풀이</h3> <h4 id="문제-요약">문제 요약</h4> <p>$N \times M$ 격자에 $0$부터 $NM-1$까지의 수가 하나씩 배정되어 있습니다. 아래와 같은 쿼리 $Q$개를 온라인으로 처리해야 합니다.</p> <ul> <li><code class="language-plaintext highlighter-rouge">swap_seats(a, b)</code>: a와 b의 위치를 바꾼 뒤, $[0, K]$번의 위치가 직사각형을 이루는 $K$의 개수를 출력</li> </ul> <p>$NM \leq 1\,000\,000 , Q \leq 50\,000$이며, 서브태스크와 각 서브태스크 별로 받을 수 있는 점수는 다음과 같습니다.</p> <table> <thead> <tr> <th>서브태스크 번호</th> <th>조건</th> <th>서브태스크 점수</th> <th>포함 서브태스크</th> <th>총 점수</th> </tr> </thead> <tbody> <tr> <td>Subtask 1</td> <td>NM ≤ 100, Q ≤ 5’000</td> <td>5점</td> <td>Subtask 1</td> <td>5점</td> </tr> <tr> <td>Subtask 2</td> <td>NM ≤ 10’000, Q ≤ 5’000</td> <td>6점</td> <td>Subtask 12</td> <td>11점</td> </tr> <tr> <td>Subtask 3</td> <td>N ≤ 1’000, M ≤ 1’000, Q ≤ 5’000</td> <td>20점</td> <td>Subtask 123</td> <td>31점</td> </tr> <tr> <td>Subtask 4</td> <td>Q ≤ 5’000, $\vert a-b \vert$ ≤ 10’000</td> <td>6점</td> <td>Subtask 124</td> <td>17점</td> </tr> <tr> <td>Subtask 3+4</td> <td>-</td> <td>-</td> <td>Subtask 1234</td> <td>37점</td> </tr> <tr> <td>Subtask 5</td> <td>N = 1</td> <td>33점</td> <td>Subtask 5</td> <td>33점</td> </tr> <tr> <td>Subtask 3+4+5</td> <td>-</td> <td>-</td> <td>Subtask 12345</td> <td>70점</td> </tr> <tr> <td>Subtask 6</td> <td>추가적인 제한 없음</td> <td>30점</td> <td>Subtask 123456</td> <td>100점</td> </tr> </tbody> </table> <h4 id="subtask-15점-on2m2q">Subtask 1(5점): $O(N^2M^2Q)$</h4> <p>수 하나를 추가하고, 직사각형 형태인지 확인하는 과정을 Naive하게 구현하면 각 쿼리를 $O(N^2M^2)$에 처리할 수 있습니다.</p> <h4 id="subtask-211점-onmq">Subtask 2(11점): $O(NMQ)$</h4> <p>$[0, K]$번이 직사각형을 이룬다는 것은 아래 식과 동치입니다. 이때 $r_1$, $r_2$, $c_1$, $c_2$는 각각 $R_i$의 Prefix Min/Max, $C_i$의 Prefix Min/Max입니다.</p> \[(r_2 - r_1 + 1)(c_2 - c_1 + 1) = K+1\] <p>$R_i, C_i$의 Prefix Min/Max는 $O(NM)$에 구할 수 있으므로 각 쿼리를 $O(NMQ)$에 해결할 수 있습니다.</p> <p><a href="http://boj.kr/ec5cf9b463354126aa7b2342bdcf5b4a">코드</a></p> <h4 id="subtask-331점-onm--qnm-log-nm">Subtask 3(31점): $O(NM + Q(N+M) \log (NM))$</h4> <p>몇 가지 관찰이 필요합니다.</p> <p><strong>관찰 1: 만들어질 수 있는 직사각형은 최대 $N+M$개</strong><br /> <strong>Proof:</strong> 가장 작은 직사각형의 크기는 $1 \times 1$, 가장 큰 직사각형의 크기는 $N \times M$이고, 직사각형이 바뀔 때마다 높이와 너비의 합이 1 이상 증가하므로 만들 수 있는 직사각형은 최대 $N+M$가지입니다.</p> <p><strong>관찰 2: $r_1, r_2, c_1, c_2$는 최대 $2(N+M)$번 변함</strong><br /> <strong>Proof:</strong> $R_i$로 가능한 값은 $N$가지, $C_i$로 가능한 값은 $M$가지입니다. 그러므로 $r_1, r_2$는 각각 최대 $N$번 변하고, $c_1, c_2$는 각각 최대 $M$번 변합니다.</p> <p><strong>관찰 3: $(R_x, C_x)$를 추가할 때, $[r_1, r_2] \times [c_1, c_2]$ 바깥에 있어야 Prefix Min/Max가 변함</strong><br /> <strong>Proof:</strong> 자명합니다.</p> <p>관찰 1을 통해 실제로 $O(N+M)$개의 수만 확인해도 된다는 사실을 알 수 있습니다.<br />관찰 2를 통해, 관찰 3에서 언급하는 조건은 최대 $2(N+M)$번만 충족한다는 것을 알 수 있습니다.</p> <p>새로운 수 $X$가 추가되는 상황을 두 가지로 분류해봅시다.</p> <ol> <li>$[r_1, r_2] \times [c_1, c_2]$에 포함되는 경우: Prefix Min/Max가 바뀌지 않습니다.<br />$(r_2 - r_1 + 1)(c_2 - c_1 + 1) = X+1$을 만족하는지만 확인하면 됩니다.</li> <li>그렇지 않은 경우: Prefix Min/Max를 갱신해야 합니다. 갱신한 뒤 직사각형 형태가 되는지 확인합니다.</li> </ol> <p>지금까지 관찰한 것을 이용해, 세그먼트 트리를 이용하는 풀이를 생각할 수 있습니다.</p> <p>$[s, e]$번에서의 $r_1, r_2, c_1, c_2$를 관리하는 세그먼트 트리를 만듭시다. 두 수의 위치를 바꾸는 것은 간단하게 처리할 수 있습니다.<br />정답을 구하는 함수 <code class="language-plaintext highlighter-rouge">Query(node, s, e)</code>는 위에서 분류한 2가지를 잘 구현하면 됩니다. 구체적으로, 아래와 같이 구현하면 됩니다.</p> <ol> <li>정점이 관리하는 구간 $[s, e]$의 수들의 위치가 $[0, s)$에 포함되는 경우: $[0, e]$가 직사각형 형태인지 확인합니다.</li> <li>현재 정점 $[s,e]$가 리프 노드($s=e$)인 경우: $[0, s]$가 직사각형 형태인지 확인합니다.</li> <li>1, 2에 속하지 않는 경우: <code class="language-plaintext highlighter-rouge">return Query(node*2, s, m) + Query(node*2+1, m+1, e)</code></li> </ol> <p>두 수를 교환하는 것은 $O(\log (NM))$에 처리할 수 있고, 정답을 구하는 <code class="language-plaintext highlighter-rouge">Query</code> 함수는 $O((N+M) \log (NM))$에 동작합니다. 그러므로 각 쿼리(<code class="language-plaintext highlighter-rouge">swap_seats</code>)를 $O((N+M) \log (NM))$에 처리할 수 있습니다.</p> <p><a href="http://boj.kr/965be1111d8748a6a9ea80f7f7f40cd6">코드</a></p> <h4 id="subtask-417점-onm--sum-vert-a---b-vert">Subtask 4(17점): $O(NM + \sum \vert a - b \vert)$</h4> <p>Subtask 2의 풀이를 조금만 변형하면 됩니다. $a$, $b$의 위치를 교환할 때 Prefix Min/Max가 바뀌는 위치는 $[a, b)$ 밖에 없습니다. 그러므로 각 쿼리를 $O(\vert a - b \vert)$에 처리할 수 있습니다.</p> <p><a href="http://boj.kr/d91ff13235a54229a85663e2f6fbb490">코드</a></p> <h4 id="subtask-3437점">Subtask 3+4(37점)</h4> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span><span class="p">(</span><span class="n">N</span> <span class="o">&lt;=</span> <span class="mi">1000</span> <span class="o">&amp;&amp;</span> <span class="n">M</span> <span class="o">&lt;=</span> <span class="mi">1000</span><span class="p">)</span> <span class="n">Subtask3</span><span class="p">();</span> <span class="k">else</span> <span class="nf">Subtask4</span><span class="p">();</span> </code></pre></div></div> <h4 id="subtask-533점-om--q-log-m">Subtask 5(33점): $O(M + Q \log M)$</h4> <p>$[0, K]$가 직사각형 형태라면, 각 수가 등장한 위치를 기록한 배열 $V$는 <code class="language-plaintext highlighter-rouge">0 0 ... 0 0 1 1 ... 1 1 0 0 ... 0 0</code>꼴이 될 것입니다. $[0, K]$가 직사각형 형태인 것과 배열 $V$에서 인접한 두 원소가 다른 쌍의 개수가 2개인 것은 필요 충분 조건이라는 것을 알 수 있습니다. 또한, 배열 $V$에서 인접한 두 원소가 다른 쌍의 개수는 항상 <strong>2 이상</strong>입니다. 그러므로 최솟값과 최솟값의 개수를 빠르게 구할 수 있으면 문제를 해결할 수 있습니다.</p> <p>구체적으로, $f(x)$를 다음과 같이 정의합시다.</p> <ul> <li>$\text{prev}(x) :=$ $(R_x, C_x) = (0, 0)$이거나 $(R_x, C_x-1)$에 있는 수가 $x$보다 크면 +1, 그렇지 않으면 -1</li> <li>$\text{next}(x) :=$ $(R_x, C_x) = (0, M-1)$이거나 $(R_x, C_x+1)$에 있는 수가 $x$보다 크면 +1, 그렇지 않으면 -1</li> <li>$f(x) := \text{prev}(x) + \text{next}(x)$</li> </ul> <p>$f(x)$의 Prefix Sum의 최솟값이 2라면 정답은 2가 등장하는 횟수가 되고, 최솟값이 2가 아니라면 정답은 0이 됩니다.</p> <p>전처리는 $O(M)$에 할 수 있고, 자리를 바꾸는 쿼리는 세그먼트 트리에 6번 업데이트를 하는 것으로 해결할 수 있습니다. ($(R_a, C_a-1), (R_a, C_a), (R_a, C_a+1), (R_b, C_b-1), (R_b, C_b), (R_b, C_b+1)$) 그러므로 각 쿼리를 $O(\log M)$에 처리할 수 있습니다.</p> <p><a href="http://boj.kr/3c23e1e4b7b54464859372eb99dda2c7">코드</a></p> <h4 id="subtask-34570점">Subtask 3+4+5(70점)</h4> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</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="n">Subtask5</span><span class="p">();</span> <span class="k">else</span> <span class="nf">if</span><span class="p">(</span><span class="n">N</span> <span class="o">&lt;=</span> <span class="mi">1000</span> <span class="o">&amp;&amp;</span> <span class="n">M</span> <span class="o">&lt;=</span> <span class="mi">1000</span><span class="p">)</span> <span class="n">Subtask4</span><span class="p">();</span> <span class="k">else</span> <span class="nf">Subtask3</span><span class="p">();</span> </code></pre></div></div> <h4 id="subtask-6100점-onm--q-log-nm">Subtask 6(100점): $O(NM + Q \log (NM))$</h4> <p>Subtask 5를 통해 기하학적 관찰을 통한 문제 해결의 가능성을 보았습니다. 1차원에서의 풀이를 2차원으로 확장해봅시다. $[0, K]$가 직사각형 형태라면, 각 수가 등장한 위치를 기록한 행렬 $V$는 아래와 같은 형태를 갖습니다.</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="p">...</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="p">...</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">1</span> <span class="mi">1</span> <span class="p">...</span> <span class="mi">1</span> <span class="mi">0</span> <span class="mi">0</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">1</span> <span class="mi">1</span> <span class="p">...</span> <span class="mi">1</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="p">...</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="p">...</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> </code></pre></div></div> <p>모든 $2 \times 2$ 행렬 $\begin{pmatrix}(R_i, C_i) &amp; (R_i, C_i+1) \ (R_i+1, C_i) &amp; (R_i+1, C_i+1)\end{pmatrix}$에서, $1$이 1개 있는 행렬이 4개, $1$이 3개 있는 행렬이 0개 존재해야 한다는 것을 알 수 있습니다.</p> <p>$1$이 1개 있는 행렬은 항상 4개 이상 존재하고, $1$이 3개 있는 행렬은 항상 0개 이상 존재합니다. 그러므로 Subtask 5의 풀이처럼 최솟값과 최솟값의 개수를 관리하는 세그먼트 트리를 사용해서 답을 구할 수 있습니다.</p> <p>전처리는 Prefix Sum을 이용해 $O(NM)$에 할 수 있고, 두 수의 위치를 바꾸는 쿼리는 세그먼트 트리를 이용해 $O(\log (NM))$에 할 수 있습니다.</p> <p><a href="http://boj.kr/a384a29c82ef4ad085f9828f87365d70">코드</a></p>JusticeHui문제 링크 http://icpc.me/20062백준19499 K-transform2021-04-19T21:45:00+00:002021-04-19T21:45:00+00:00https://justicehui.github.io/ps/2021/04/19/BOJ19499<h3 id="문제-링크">문제 링크</h3> <ul> <li>http://icpc.me/19499</li> </ul> <h3 id="사용-알고리즘">사용 알고리즘</h3> <ul> <li>FFT</li> <li>Kitamasa</li> <li>Fenwick Tree</li> </ul> <h3 id="시간복잡도">시간복잡도</h3> <ul> <li>$O(K \log K \log M)$</li> </ul> <h3 id="풀이">풀이</h3> <p>정확히 $T$번 연산해서 $N$이 되는 경우의 수를 $g(T, N)$라고 정의합시다. $g(T, N)$은 아래와 같이 표현할 수 있습니다.</p> \[g(T, N) = \begin{cases} 1 \text{, if } T = 0 \\ g(T-1, Nk) \text{, if } k \vert (N+1) \\ g(T-1, N+1) + g(T-1, Nk) \text{, otherwise} \end{cases}\] <p>입력으로 주어진 $k, m, mod$에 대해 $g(k, m) \mod mod$가 문제의 정답이 됩니다.</p> <p>여러 $k$에 대해 로컬에서 작은 항을 계산해본 뒤 berlekamp-massey를 돌려보면 선형 점화식을 얻을 수 있습니다. $D(m)$을 문제의 정답이라고 정의하면, 점화식은 아래와 같이 나옵니다.</p> \[D(m) = \begin{cases}2^m \text{, if } m &lt; k-1 \\ 2^m-1 \text{, if } m = k-1 \\ \displaystyle \sum_{i=1}^{k} D(m-i) \text{, otherwise}\end{cases}\] <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><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">lll</span> <span class="o">=</span> <span class="n">__int128_t</span><span class="p">;</span> <span class="kt">int</span> <span class="n">K</span><span class="p">;</span> <span class="kt">int</span> <span class="nf">f</span><span class="p">(</span><span class="kt">int</span> <span class="n">T</span><span class="p">,</span> <span class="n">lll</span> <span class="n">N</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">T</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="mi">1</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">1</span><span class="p">)</span> <span class="o">%</span> <span class="n">K</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="n">f</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="n">N</span><span class="o">*</span><span class="n">K</span><span class="p">);</span> <span class="k">else</span> <span class="k">return</span> <span class="p">(</span><span class="n">f</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="n">N</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">f</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="n">N</span><span class="o">*</span><span class="n">K</span><span class="p">))</span> <span class="o">%</span> <span class="n">MOD</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">_k</span><span class="p">){</span> <span class="n">K</span> <span class="o">=</span> <span class="n">_k</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="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="o">*</span><span class="n">K</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">V</span><span class="p">.</span><span class="n">push_back</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="mi">1</span><span class="p">));</span> <span class="k">auto</span> <span class="n">R</span> <span class="o">=</span> <span class="n">berlekamp_massey</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">K</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="p">)</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">K</span> <span class="o">&lt;&lt;</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">R</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> </code></pre></div></div> <p>$k \leq 10^4, m \leq 10^{18}$이므로 Kitamasa와 FFT를 사용하면 $O(k \log k \log m)$에 점화식을 계산할 수 있습니다.<br /> 하지만, FFT를 사용한 다항식 나눗셈은 <strong>느린</strong> $O(k \log k)$에 속하기 때문에 2초라는 빡빡한 시간 제한을 통과하기 어렵습니다. 최적화를 해야 합니다.</p> <p>Divisor를 보면, 항상 $C_k(x) = x^k - x^{k-1} - x^{k-2} - x^{k-3} - \cdots - 1$ 꼴이라는 것을 알 수 있습니다. 어떤 다항식을 $C_k(x)$로 나눈 나머지를 구하는 과정을 손으로 직접 계산해보면, 어떤 수 $c$를 적당한 구간 $[i-k, i-1]$에 더하는 연산을 여러 번 수행한다는 것을 알 수 있습니다. 우리는 이런 연산을 Fenwick Tree를 사용해 매우 빠르게 수행할 수 있습니다. 그러므로 다항식 나눗셈을 <strong>빠른</strong> $O(k \log k)$에 할 수 있고, AC를 받을 수 있습니다.</p> <h3 id="전체-코드">전체 코드</h3> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/****************************** Author: jhnah917(Justice_Hui) g++ -std=c++17 -DLOCAL -O3 -lm -mavx -mavx2 -mfma ******************************/</span> <span class="cp">#pragma GCC optimize("O3") #pragma GCC target("avx,avx2,fma") #include &lt;bits/stdc++.h&gt; #include &lt;smmintrin.h&gt; #include &lt;immintrin.h&gt; #define all(v) v.begin(), v.end() #define sz(v) (int)(v.size()) </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">int64_t</span><span class="p">;</span> <span class="k">using</span> <span class="n">poly</span> <span class="o">=</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">ll</span><span class="o">&gt;</span><span class="p">;</span> <span class="n">ll</span> <span class="n">M</span><span class="p">;</span> <span class="kt">int</span> <span class="n">K</span><span class="p">,</span> <span class="n">MOD</span><span class="p">;</span> <span class="kt">int</span> <span class="nf">Norm</span><span class="p">(</span><span class="n">ll</span> <span class="n">v</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">v</span> <span class="o">&lt;</span> <span class="o">-</span><span class="n">MOD</span> <span class="o">||</span> <span class="n">v</span> <span class="o">&gt;=</span> <span class="n">MOD</span><span class="p">)</span> <span class="n">v</span> <span class="o">%=</span> <span class="n">MOD</span><span class="p">;</span> <span class="k">return</span> <span class="n">v</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="o">?</span> <span class="n">v</span> <span class="o">+</span> <span class="n">MOD</span> <span class="o">:</span> <span class="n">v</span><span class="p">;</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">Norm</span><span class="p">(</span><span class="n">poly</span> <span class="o">&amp;</span><span class="n">a</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">a</span><span class="p">)</span> <span class="n">i</span> <span class="o">=</span> <span class="n">Norm</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> <span class="k">while</span><span class="p">(</span><span class="n">a</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">a</span><span class="p">.</span><span class="n">back</span><span class="p">())</span> <span class="n">a</span><span class="p">.</span><span class="n">pop_back</span><span class="p">();</span> <span class="p">}</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">){</span> <span class="k">return</span> <span class="n">a</span><span class="o">+</span><span class="n">b</span><span class="o">&gt;=</span><span class="n">MOD</span> <span class="o">?</span> <span class="n">a</span><span class="o">+</span><span class="n">b</span><span class="o">-</span><span class="n">MOD</span> <span class="o">:</span> <span class="n">a</span><span class="o">+</span><span class="n">b</span><span class="p">;</span> <span class="p">}</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="nf">Sub</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">){</span> <span class="k">return</span> <span class="n">a</span> <span class="o">&gt;=</span> <span class="n">b</span> <span class="o">?</span> <span class="n">a</span><span class="o">-</span><span class="n">b</span><span class="o">+</span><span class="n">MOD</span> <span class="o">:</span> <span class="n">a</span><span class="o">-</span><span class="n">b</span><span class="p">;</span> <span class="p">}</span> <span class="n">__m256d</span> <span class="nf">mult</span><span class="p">(</span><span class="n">__m256d</span> <span class="n">a</span><span class="p">,</span> <span class="n">__m256d</span> <span class="n">b</span><span class="p">){</span> <span class="n">__m256d</span> <span class="n">c</span> <span class="o">=</span> <span class="n">_mm256_movedup_pd</span><span class="p">(</span><span class="n">a</span><span class="p">);</span> <span class="n">__m256d</span> <span class="n">d</span> <span class="o">=</span> <span class="n">_mm256_shuffle_pd</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="mi">15</span><span class="p">);</span> <span class="n">__m256d</span> <span class="n">cb</span> <span class="o">=</span> <span class="n">_mm256_mul_pd</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span> <span class="n">__m256d</span> <span class="n">db</span> <span class="o">=</span> <span class="n">_mm256_mul_pd</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span> <span class="n">__m256d</span> <span class="n">e</span> <span class="o">=</span> <span class="n">_mm256_shuffle_pd</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="n">db</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span> <span class="n">__m256d</span> <span class="n">r</span> <span class="o">=</span> <span class="n">_mm256_addsub_pd</span><span class="p">(</span><span class="n">cb</span><span class="p">,</span> <span class="n">e</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">fft</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="n">__m128d</span> <span class="n">a</span><span class="p">[],</span> <span class="kt">bool</span> <span class="n">invert</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="o">++</span><span class="n">i</span><span class="p">){</span> <span class="kt">int</span> <span class="n">bit</span> <span class="o">=</span> <span class="n">n</span><span class="o">&gt;&gt;</span><span class="mi">1</span><span class="p">;</span> <span class="k">for</span><span class="p">(;</span><span class="n">j</span><span class="o">&gt;=</span><span class="n">bit</span><span class="p">;</span><span class="n">bit</span><span class="o">&gt;&gt;=</span><span class="mi">1</span><span class="p">)</span> <span class="n">j</span> <span class="o">-=</span> <span class="n">bit</span><span class="p">;</span> <span class="n">j</span> <span class="o">+=</span> <span class="n">bit</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">j</span><span class="p">)</span> <span class="n">swap</span><span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">a</span><span class="p">[</span><span class="n">j</span><span class="p">]);</span> <span class="p">}</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">len</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">lv</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">len</span><span class="o">&lt;=</span><span class="n">n</span><span class="p">;</span> <span class="n">len</span><span class="o">&lt;&lt;=</span><span class="mi">1</span><span class="p">,</span> <span class="n">lv</span><span class="o">++</span><span class="p">){</span> <span class="kt">double</span> <span class="n">ang</span> <span class="o">=</span> <span class="mi">2</span><span class="o">*</span><span class="n">M_PI</span><span class="o">/</span><span class="n">len</span><span class="o">*</span><span class="p">(</span><span class="n">invert</span><span class="o">?-</span><span class="mi">1</span><span class="o">:</span><span class="mi">1</span><span class="p">);</span> <span class="n">__m256d</span> <span class="n">wlen</span><span class="p">;</span> <span class="n">wlen</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">cos</span><span class="p">(</span><span class="n">ang</span><span class="p">),</span> <span class="n">wlen</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">sin</span><span class="p">(</span><span class="n">ang</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="n">len</span><span class="p">){</span> <span class="n">__m256d</span> <span class="n">w</span><span class="p">;</span> <span class="n">w</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="n">w</span><span class="p">[</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="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="n">len</span><span class="o">/</span><span class="mi">2</span><span class="p">;</span> <span class="o">++</span><span class="n">j</span><span class="p">){</span> <span class="n">w</span> <span class="o">=</span> <span class="n">_mm256_permute2f128_pd</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">w</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="n">wlen</span> <span class="o">=</span> <span class="n">_mm256_insertf128_pd</span><span class="p">(</span><span class="n">wlen</span><span class="p">,</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="n">j</span><span class="o">+</span><span class="n">len</span><span class="o">/</span><span class="mi">2</span><span class="p">],</span> <span class="mi">1</span><span class="p">);</span> <span class="n">w</span> <span class="o">=</span> <span class="n">mult</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">wlen</span><span class="p">);</span> <span class="n">__m128d</span> <span class="n">vw</span> <span class="o">=</span> <span class="n">_mm256_extractf128_pd</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="n">__m128d</span> <span class="n">u</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="n">j</span><span class="p">];</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">_mm_add_pd</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">vw</span><span class="p">);</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="n">j</span><span class="o">+</span><span class="n">len</span><span class="o">/</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">_mm_sub_pd</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">vw</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">invert</span><span class="p">){</span> <span class="n">__m128d</span> <span class="n">inv</span><span class="p">;</span> <span class="n">inv</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">inv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mf">1.0</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="o">++</span><span class="n">i</span><span class="p">)</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">_mm_mul_pd</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">inv</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">int64_t</span><span class="o">&gt;</span> <span class="n">multiply</span><span class="p">(</span><span class="k">const</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int64_t</span><span class="o">&gt;&amp;</span> <span class="n">v</span><span class="p">,</span> <span class="k">const</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int64_t</span><span class="o">&gt;&amp;</span> <span class="n">w</span><span class="p">){</span> <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="k">while</span><span class="p">(</span><span class="n">n</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">+</span><span class="n">w</span><span class="p">.</span><span class="n">size</span><span class="p">())</span> <span class="n">n</span><span class="o">&lt;&lt;=</span><span class="mi">1</span><span class="p">;</span> <span class="n">__m128d</span><span class="o">*</span> <span class="n">fv</span> <span class="o">=</span> <span class="k">new</span> <span class="n">__m128d</span><span class="p">[</span><span class="n">n</span><span class="p">];</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="n">fv</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">fv</span><span class="p">[</span><span class="n">i</span><span class="p">][</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="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="n">size</span><span class="p">();</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="n">fv</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">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="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">w</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="n">fv</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">1</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="n">fft</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">fv</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="mi">2</span><span class="p">){</span> <span class="n">__m256d</span> <span class="n">a</span><span class="p">;</span> <span class="n">a</span> <span class="o">=</span> <span class="n">_mm256_insertf128_pd</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">fv</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="mi">0</span><span class="p">);</span> <span class="n">a</span> <span class="o">=</span> <span class="n">_mm256_insertf128_pd</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">fv</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">1</span><span class="p">);</span> <span class="n">a</span> <span class="o">=</span> <span class="n">mult</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">fv</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">_mm256_extractf128_pd</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="n">fv</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">_mm256_extractf128_pd</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="p">}</span> <span class="n">fft</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">fv</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int64_t</span><span class="o">&gt;</span> <span class="n">ret</span><span class="p">(</span><span class="n">n</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="n">ret</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int64_t</span><span class="p">)</span><span class="n">llround</span><span class="p">(</span><span class="n">fv</span><span class="p">[</span><span class="n">i</span><span class="p">][</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">delete</span><span class="p">[]</span> <span class="n">fv</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="n">tree</span><span class="p">[</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="mi">15</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">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">2</span><span class="p">;</span> <span class="n">x</span><span class="o">&lt;</span><span class="p">(</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="mi">15</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">tree</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">query</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">2</span><span class="p">;</span> <span class="n">x</span><span class="o">&gt;</span><span class="mi">0</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">tree</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="n">poly</span> <span class="nf">mul</span><span class="p">(</span><span class="k">const</span> <span class="n">poly</span> <span class="o">&amp;</span><span class="n">a</span><span class="p">,</span> <span class="k">const</span> <span class="n">poly</span> <span class="o">&amp;</span><span class="n">b</span><span class="p">){</span> <span class="k">auto</span> <span class="n">res</span> <span class="o">=</span> <span class="n">multiply</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">Norm</span><span class="p">(</span><span class="n">res</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">poly</span> <span class="nf">rem</span><span class="p">(</span><span class="k">const</span> <span class="n">poly</span> <span class="o">&amp;</span><span class="n">a</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">1</span> <span class="o">&gt;</span> <span class="n">a</span><span class="p">.</span><span class="n">size</span><span class="p">())</span> <span class="k">return</span> <span class="n">a</span><span class="p">;</span> <span class="n">memset</span><span class="p">(</span><span class="n">tree</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span> <span class="n">tree</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">a</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">update</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]),</span> <span class="n">update</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</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="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&gt;=</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="kt">int</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Norm</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="n">update</span><span class="p">(</span><span class="n">i</span><span class="o">-</span><span class="n">K</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">i</span><span class="p">,</span> <span class="o">-</span><span class="n">t</span><span class="p">);</span> <span class="p">}</span> <span class="n">poly</span> <span class="n">ret</span><span class="p">(</span><span class="n">K</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">K</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">ret</span><span class="p">[</span><span class="n">i</span><span class="p">]</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">Norm</span><span class="p">(</span><span class="n">ret</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="n">poly</span> <span class="nf">get</span><span class="p">(</span><span class="n">ll</span> <span class="n">k</span><span class="p">){</span> <span class="n">poly</span> <span class="n">d</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">},</span> <span class="n">xn</span> <span class="o">=</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="k">while</span><span class="p">(</span><span class="n">k</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">k</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="n">d</span> <span class="o">=</span> <span class="n">rem</span><span class="p">(</span><span class="n">mul</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">xn</span><span class="p">));</span> <span class="n">k</span> <span class="o">&gt;&gt;=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">xn</span> <span class="o">=</span> <span class="n">rem</span><span class="p">(</span><span class="n">mul</span><span class="p">(</span><span class="n">xn</span><span class="p">,</span> <span class="n">xn</span><span class="p">));</span> <span class="p">}</span> <span class="k">return</span> <span class="n">d</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">M</span> <span class="o">&gt;&gt;</span> <span class="n">MOD</span><span class="p">;</span> <span class="n">poly</span> <span class="n">D</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">pw</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">K</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">,</span> <span class="n">pw</span><span class="o">=</span><span class="n">Add</span><span class="p">(</span><span class="n">pw</span><span class="p">,</span> <span class="n">pw</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">K</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span> <span class="n">D</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">pw</span><span class="p">);</span> <span class="k">else</span> <span class="n">D</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">Sub</span><span class="p">(</span><span class="n">pw</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span> <span class="p">}</span> <span class="k">auto</span> <span class="n">C</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="n">M</span><span class="p">);</span> <span class="n">ll</span> <span class="n">ans</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">ans</span> <span class="o">+=</span> <span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">D</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">M</span> <span class="o">&lt;</span> <span class="n">K</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">M</span><span class="p">];</span> <span class="k">else</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">Norm</span><span class="p">(</span><span class="n">ans</span><span class="p">);</span> <span class="p">}</span> </code></pre></div></div>JusticeHui문제 링크 http://icpc.me/19499백준10014 Traveling Saga Problem2021-04-16T21:02:00+00:002021-04-16T21:02:00+00:00https://justicehui.github.io/ps/2021/04/16/BOJ10014<h3 id="문제-링크">문제 링크</h3> <ul> <li>http://icpc.me/10014</li> </ul> <h3 id="사용-알고리즘">사용 알고리즘</h3> <ul> <li>Centroid</li> <li>트리 이진 변환</li> </ul> <h3 id="시간복잡도">시간복잡도</h3> <ul> <li>$O((N+Q) \log^2 N)$</li> </ul> <h3 id="풀이">풀이</h3> <p>어떤 정점에서 가장 먼 정점을 찾는 쿼리를 여러 번 수행하는 문제입니다. Centroid Decomposition을 이용하면 될 것 같다는 생각이 듭니다.</p> <p>입력으로 주어진 트리 $T$의 정점 $v$와 가장 멀리 떨어져있는 정점 $u$는, Centroid Tree $C_T$에서 $v$의 조상 $p$를 따라가면서 $p$의 $C_T$ 상에서의 자손을 보면 됩니다. 이때 $C_T$의 각 정점에서는, 그 서브 트리에 속하는 정점 $x$에 대해 $(Dist(p, x), x)$를 max heap으로 저장하고 있습니다.<br /> $u$는 $v$와 다른 서브트리에 속해야 하기 때문에, $v$의 $C_T$ 상의 조상 $p$의 자식 정점을 모두 순회해야 합니다.</p> <p>만약 트리가 성게 그래프(star graph)라면 Centroid Tree의 정점의 Degree가 $N-1$이 돼서 각 쿼리가 $O(N \log^2 N)$이 됩니다. 트리를 이진 트리로 바꿔주면 자식의 개수(정점의 Degree)가 최대 3이 되므로 각 쿼리를 $O(3 \log^2 N)$에 처리할 수 있습니다.</p> <h3 id="전체-코드">전체 코드</h3> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/****************************** Author: jhnah917(Justice_Hui) g++ -std=c++17 -DLOCAL ******************************/</span> <span class="cp">#include &lt;bits/stdc++.h&gt; #define x first #define y second #define all(v) v.begin(), v.end() #define compress(v) sort(all(v)), v.erase(unique(all(v)), v.end()) #define IDX(v, x) (lower_bound(all(v), x) - v.begin()) </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">uint</span> <span class="o">=</span> <span class="kt">unsigned</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">ull</span> <span class="o">=</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="kt">long</span><span class="p">;</span> <span class="k">using</span> <span class="n">PII</span> <span class="o">=</span> <span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span><span class="p">;</span> <span class="k">constexpr</span> <span class="kt">int</span> <span class="n">SZ</span> <span class="o">=</span> <span class="mi">505050</span><span class="p">,</span> <span class="n">LG</span> <span class="o">=</span> <span class="mi">20</span><span class="p">,</span> <span class="n">INF</span> <span class="o">=</span> <span class="mh">0x3f3f3f3f</span><span class="p">;</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">pv</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">Inp</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="n">PII</span><span class="o">&gt;</span> <span class="n">G</span><span class="p">[</span><span class="n">SZ</span><span class="p">];</span> <span class="kt">int</span> <span class="n">S</span><span class="p">[</span><span class="n">SZ</span><span class="p">],</span> <span class="n">U</span><span class="p">[</span><span class="n">SZ</span><span class="p">],</span> <span class="n">P</span><span class="p">[</span><span class="n">LG</span><span class="p">][</span><span class="n">SZ</span><span class="p">],</span> <span class="n">D</span><span class="p">[</span><span class="n">SZ</span><span class="p">],</span> <span class="n">C</span><span class="p">[</span><span class="n">SZ</span><span class="p">];</span> <span class="kt">int</span> <span class="n">CP</span><span class="p">[</span><span class="n">SZ</span><span class="p">],</span> <span class="n">CID</span><span class="p">[</span><span class="n">SZ</span><span class="p">];</span> <span class="n">priority_queue</span><span class="o">&lt;</span><span class="n">PII</span><span class="o">&gt;</span> <span class="n">Info</span><span class="p">[</span><span class="n">SZ</span><span class="p">][</span><span class="mi">4</span><span class="p">];</span> <span class="kt">void</span> <span class="nf">Flush</span><span class="p">(</span><span class="n">priority_queue</span><span class="o">&lt;</span><span class="n">PII</span><span class="o">&gt;</span> <span class="o">&amp;</span><span class="n">pq</span><span class="p">){</span> <span class="k">while</span><span class="p">(</span><span class="n">pq</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">U</span><span class="p">[</span><span class="n">pq</span><span class="p">.</span><span class="n">top</span><span class="p">().</span><span class="n">y</span><span class="p">])</span> <span class="n">pq</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span> <span class="p">}</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="kt">int</span> <span class="n">x</span><span class="p">){</span> <span class="n">G</span><span class="p">[</span><span class="n">s</span><span class="p">].</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">x</span><span class="p">);</span> <span class="n">G</span><span class="p">[</span><span class="n">e</span><span class="p">].</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">s</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">Rebuild</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">lst</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="n">i</span> <span class="o">:</span> <span class="n">Inp</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="k">continue</span><span class="p">;</span> <span class="n">Rebuild</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">if</span><span class="p">(</span><span class="n">lst</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</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="mi">1</span><span class="p">),</span> <span class="n">lst</span> <span class="o">=</span> <span class="n">v</span><span class="p">;</span> <span class="k">else</span><span class="p">{</span> <span class="kt">int</span> <span class="n">dummy</span> <span class="o">=</span> <span class="o">++</span><span class="n">pv</span><span class="p">;</span> <span class="n">AddEdge</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="n">dummy</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="n">AddEdge</span><span class="p">(</span><span class="n">dummy</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="n">lst</span> <span class="o">=</span> <span class="n">dummy</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">Init</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="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">LG</span><span class="p">;</span> <span class="n">i</span><span class="o">++</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">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">P</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">P</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="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="p">.</span><span class="n">x</span> <span class="o">==</span> <span class="n">b</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span> <span class="n">P</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="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span><span class="p">;</span> <span class="n">D</span><span class="p">[</span><span class="n">i</span><span class="p">.</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">D</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">.</span><span class="n">x</span><span class="p">]</span> <span class="o">=</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">i</span><span class="p">.</span><span class="n">y</span><span class="p">;</span> <span class="n">Init</span><span class="p">(</span><span class="n">i</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">v</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">LCA</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</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">D</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">D</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="n">swap</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">);</span> <span class="kt">int</span> <span class="n">diff</span> <span class="o">=</span> <span class="n">D</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">-</span> <span class="n">D</span><span class="p">[</span><span class="n">v</span><span class="p">];</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">diff</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">,</span> <span class="n">diff</span><span class="o">&gt;&gt;=</span><span class="mi">1</span><span class="p">)</span> <span class="k">if</span><span class="p">(</span><span class="n">diff</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="n">u</span> <span class="o">=</span> <span class="n">P</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">u</span><span class="p">];</span> <span class="k">if</span><span class="p">(</span><span class="n">u</span> <span class="o">==</span> <span class="n">v</span><span class="p">)</span> <span class="k">return</span> <span class="n">u</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="n">LG</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="o">~</span><span class="n">i</span><span class="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">P</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">u</span><span class="p">]</span> <span class="o">!=</span> <span class="n">P</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">u</span> <span class="o">=</span> <span class="n">P</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">u</span><span class="p">],</span> <span class="n">v</span> <span class="o">=</span> <span class="n">P</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">P</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">u</span><span class="p">];</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">Dist</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</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">C</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</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="mi">2</span><span class="o">*</span><span class="n">C</span><span class="p">[</span><span class="n">LCA</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="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="n">i</span> <span class="o">:</span> <span class="n">G</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">U</span><span class="p">[</span><span class="n">i</span><span class="p">.</span><span class="n">x</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="n">i</span><span class="p">.</span><span class="n">x</span> <span class="o">!=</span> <span class="n">b</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">x</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">tot</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="o">!</span><span class="n">U</span><span class="p">[</span><span class="n">i</span><span class="p">.</span><span class="n">x</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="n">i</span><span class="p">.</span><span class="n">x</span> <span class="o">!=</span> <span class="n">b</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="n">x</span><span class="p">]</span><span class="o">*</span><span class="mi">2</span> <span class="o">&gt;</span> <span class="n">tot</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">x</span><span class="p">,</span> <span class="n">tot</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">Gather</span><span class="p">(</span><span class="kt">int</span> <span class="n">rt</span><span class="p">,</span> <span class="kt">int</span> <span class="n">id</span><span class="p">,</span> <span class="kt">int</span> <span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">,</span> <span class="kt">int</span> <span class="n">d</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="n">v</span> <span class="o">&lt;=</span> <span class="n">N</span><span class="p">)</span> <span class="n">Info</span><span class="p">[</span><span class="n">rt</span><span class="p">][</span><span class="n">id</span><span class="p">].</span><span class="n">emplace</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">v</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="n">i</span> <span class="o">:</span> <span class="n">G</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">U</span><span class="p">[</span><span class="n">i</span><span class="p">.</span><span class="n">x</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="n">i</span><span class="p">.</span><span class="n">x</span> <span class="o">!=</span> <span class="n">b</span><span class="p">)</span> <span class="n">Gather</span><span class="p">(</span><span class="n">rt</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="n">x</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">d</span><span class="o">+</span><span class="n">i</span><span class="p">.</span><span class="n">y</span><span class="p">);</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">CD</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">cent</span> <span class="o">=</span> <span class="n">GetCent</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">GetSize</span><span class="p">(</span><span class="n">v</span><span class="p">));</span> <span class="n">U</span><span class="p">[</span><span class="n">cent</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">CP</span><span class="p">[</span><span class="n">cent</span><span class="p">]</span> <span class="o">=</span> <span class="n">b</span><span class="p">;</span> <span class="kt">int</span> <span class="n">cnt</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">cent</span> <span class="o">&lt;=</span> <span class="n">N</span><span class="p">)</span> <span class="n">Info</span><span class="p">[</span><span class="n">cent</span><span class="p">][</span><span class="mi">0</span><span class="p">].</span><span class="n">emplace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">cent</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">cent</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">x</span><span class="p">])</span> <span class="n">Gather</span><span class="p">(</span><span class="n">cent</span><span class="p">,</span> <span class="n">cnt</span><span class="o">++</span><span class="p">,</span> <span class="n">i</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">cent</span><span class="p">,</span> <span class="n">i</span><span class="p">.</span><span class="n">y</span><span class="p">);</span> <span class="n">cnt</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">cent</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">x</span><span class="p">])</span> <span class="n">CID</span><span class="p">[</span><span class="n">CD</span><span class="p">(</span><span class="n">i</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">cent</span><span class="p">)]</span> <span class="o">=</span> <span class="n">cnt</span><span class="o">++</span><span class="p">;</span> <span class="k">return</span> <span class="n">cent</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">Query</span><span class="p">(</span><span class="kt">int</span> <span class="n">v</span><span class="p">){</span> <span class="n">PII</span> <span class="n">mx</span><span class="p">(</span><span class="o">-</span><span class="n">INF</span><span class="p">,</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="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="n">v</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">!=-</span><span class="mi">1</span><span class="p">;</span> <span class="n">j</span><span class="o">=</span><span class="n">CID</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">i</span><span class="o">=</span><span class="n">CP</span><span class="p">[</span><span class="n">i</span><span class="p">]){</span> <span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="n">Dist</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span> <span class="k">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="mi">4</span><span class="p">;</span> <span class="n">k</span><span class="o">++</span><span class="p">){</span> <span class="n">Flush</span><span class="p">(</span><span class="n">Info</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="k">if</span><span class="p">(</span><span class="n">j</span> <span class="o">==</span> <span class="n">k</span> <span class="o">||</span> <span class="n">Info</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">empty</span><span class="p">())</span> <span class="k">continue</span><span class="p">;</span> <span class="k">auto</span> <span class="p">[</span><span class="n">d</span><span class="p">,</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="n">Info</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">top</span><span class="p">();</span> <span class="n">mx</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">mx</span><span class="p">,</span> <span class="n">PII</span><span class="p">(</span><span class="n">d</span><span class="o">+</span><span class="n">c</span><span class="p">,</span> <span class="n">u</span><span class="p">));</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="n">y</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">s</span><span class="p">,</span> <span class="n">e</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">s</span> <span class="o">&gt;&gt;</span> <span class="n">e</span><span class="p">;</span> <span class="n">Inp</span><span class="p">[</span><span class="n">s</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">e</span><span class="p">);</span> <span class="n">Inp</span><span class="p">[</span><span class="n">e</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> <span class="p">}</span> <span class="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">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">G</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">reserve</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span> <span class="n">pv</span> <span class="o">=</span> <span class="n">N</span><span class="p">;</span> <span class="n">Rebuild</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="n">Init</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="n">CD</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="n">memset</span><span class="p">(</span><span class="n">U</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span> <span class="n">U</span><span class="p">);</span> <span class="kt">int</span> <span class="n">lst</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">U</span><span class="p">[</span><span class="n">lst</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">lst</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="n">lst</span> <span class="o">=</span> <span class="n">Query</span><span class="p">(</span><span class="n">lst</span><span class="p">);</span> <span class="n">U</span><span class="p">[</span><span class="n">lst</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">lst</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div>JusticeHui문제 링크 http://icpc.me/10014백준2598 기둥만들기2021-04-15T20:52:00+00:002021-04-15T20:52:00+00:00https://justicehui.github.io/koi/2021/04/15/BOJ2598<h3 id="문제-링크">문제 링크</h3> <ul> <li>http://icpc.me/2598</li> </ul> <h3 id="문제-출처">문제 출처</h3> <ul> <li>2004 KOI 초등부 3번</li> </ul> <h3 id="풀이">풀이</h3> <p>브루트포스를 열심히 하는 문제입니다.<br /> (1) 기둥의 상태를 잘 표현하는 것, (2) 회전했을 때 동일한 기둥인지 판별하는 것, (3) 정육면체의 상태를 잘 표현하는 것, 3가지를 어떻게 효율적으로 구현할지 고민해보는 것이 좋습니다.</p> <p>색이 4가지 종류 밖에 없기 때문에 각 색깔은 2비트로 표현할 수 있습니다. 옆면에 등장하는 16개의 면과 윗면까지 총 17개의 면을 표현해야 하므로 34비트가 필요합니다. 64bit 정수형으로 저장할 수 있습니다.</p> <p>회전했을 때 동일한 기둥인지 판별하는 것은, 옆면들의 minimum cyclic shift를 저장하면 됩니다. 다시 말해, 4개의 옆면을 회전시켰을 때 사전순으로 가장 앞서는 것만 저장하면 됩니다. (ex. <code class="language-plaintext highlighter-rouge">2031 / 0312 / 3120 / 1203</code> 중 <code class="language-plaintext highlighter-rouge">0312</code>만 저장)</p> <p>정육면체의 상태를 나타내는 것은 위/앞/오른쪽, 총 3개의 면을 고정하면 됩니다.</p> <p>위 3가지를 잘 조합하면 문제를 풀 수 있습니다.</p> <h3 id="전체-코드">전체 코드</h3> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/****************************** Author: jhnah917(Justice_Hui) g++ -std=c++17 -DLOCAL ******************************/</span> <span class="cp">#include &lt;bits/stdc++.h&gt; #define x first #define y second #define all(v) v.begin(), v.end() #define compress(v) sort(all(v)), v.erase(unique(all(v)), v.end()) </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">const</span> <span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">4</span><span class="o">&gt;</span> <span class="n">SIDE</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</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="mi">4</span><span class="p">,</span><span class="mi">3</span><span class="p">},</span> <span class="p">{</span><span class="mi">5</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">0</span><span class="p">},</span> <span class="p">{</span><span class="mi">5</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">1</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">5</span><span class="p">},</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="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">1</span><span class="p">}</span> <span class="p">};</span> <span class="n">string</span> <span class="n">A</span><span class="p">[</span><span class="mi">4</span><span class="p">];</span> <span class="n">map</span><span class="o">&lt;</span><span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">3</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">4</span><span class="o">&gt;&gt;</span> <span class="n">mp</span><span class="p">;</span> <span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">4</span><span class="o">&gt;</span> <span class="n">fst</span><span class="p">[</span><span class="mi">6</span><span class="p">];</span> <span class="kt">int</span> <span class="n">C_MAP</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="nf">ID</span><span class="p">(</span><span class="kt">char</span> <span class="n">c</span><span class="p">){</span> <span class="k">return</span> <span class="n">C_MAP</span><span class="p">[</span><span class="n">c</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">C_MAP</span><span class="p">[</span><span class="sc">'R'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">C_MAP</span><span class="p">[</span><span class="sc">'G'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">C_MAP</span><span class="p">[</span><span class="sc">'B'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">C_MAP</span><span class="p">[</span><span class="sc">'Y'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="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">6</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">3</span><span class="o">&gt;</span> <span class="n">a</span><span class="p">;</span> <span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">4</span><span class="o">&gt;</span> <span class="n">b</span> <span class="o">=</span> <span class="n">SIDE</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">]</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">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">4</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="n">a</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">b</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> <span class="n">a</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">b</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span> <span class="n">mp</span><span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">=</span> <span class="n">b</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">j</span><span class="p">)</span> <span class="n">fst</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">rotate</span><span class="p">(</span><span class="n">b</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">b</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">b</span><span class="p">.</span><span class="n">end</span><span class="p">());</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="n">ll</span> <span class="nf">Norm</span><span class="p">(</span><span class="n">ll</span> <span class="n">bit</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">vec</span><span class="p">,</span> <span class="n">mn</span><span class="p">;</span> <span class="n">vec</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">bit</span> <span class="o">&amp;</span> <span class="mi">3</span><span class="p">);</span> <span class="n">bit</span> <span class="o">&gt;&gt;=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">vec</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">bit</span> <span class="o">&amp;</span> <span class="mi">255</span><span class="p">);</span> <span class="n">bit</span> <span class="o">&gt;&gt;=</span> <span class="mi">8</span><span class="p">;</span> <span class="n">vec</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">bit</span> <span class="o">&amp;</span> <span class="mi">255</span><span class="p">);</span> <span class="n">bit</span> <span class="o">&gt;&gt;=</span> <span class="mi">8</span><span class="p">;</span> <span class="n">vec</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">bit</span> <span class="o">&amp;</span> <span class="mi">255</span><span class="p">);</span> <span class="n">bit</span> <span class="o">&gt;&gt;=</span> <span class="mi">8</span><span class="p">;</span> <span class="n">vec</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">bit</span> <span class="o">&amp;</span> <span class="mi">255</span><span class="p">);</span> <span class="n">bit</span> <span class="o">&gt;&gt;=</span> <span class="mi">8</span><span class="p">;</span> <span class="n">reverse</span><span class="p">(</span><span class="n">all</span><span class="p">(</span><span class="n">vec</span><span class="p">));</span> <span class="n">mn</span> <span class="o">=</span> <span class="n">vec</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">4</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="n">rotate</span><span class="p">(</span><span class="n">vec</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">vec</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">vec</span><span class="p">.</span><span class="n">begin</span><span class="p">()</span><span class="o">+</span><span class="mi">4</span><span class="p">);</span> <span class="n">mn</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">mn</span><span class="p">,</span> <span class="n">vec</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">i</span><span class="o">&lt;</span><span class="mi">4</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">bit</span> <span class="o">=</span> <span class="n">bit</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span> <span class="o">|</span> <span class="n">mn</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="n">bit</span> <span class="o">=</span> <span class="n">bit</span> <span class="o">&lt;&lt;</span> <span class="mi">2</span> <span class="o">|</span> <span class="n">mn</span><span class="p">.</span><span class="n">back</span><span class="p">();</span> <span class="k">return</span> <span class="n">bit</span><span class="p">;</span> <span class="p">}</span> <span class="n">ll</span> <span class="nf">Check</span><span class="p">(</span><span class="k">const</span> <span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">4</span><span class="o">&gt;</span> <span class="o">&amp;</span><span class="n">a</span><span class="p">,</span> <span class="k">const</span> <span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">4</span><span class="o">&gt;</span> <span class="o">&amp;</span><span class="n">b</span><span class="p">,</span> <span class="k">const</span> <span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">4</span><span class="o">&gt;</span> <span class="o">&amp;</span><span class="n">c</span><span class="p">,</span> <span class="k">const</span> <span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">4</span><span class="o">&gt;</span> <span class="o">&amp;</span><span class="n">d</span><span class="p">,</span> <span class="kt">int</span> <span class="n">top</span><span class="p">){</span> <span class="n">ll</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="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">4</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">bit</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">4</span><span class="o">&gt;</span> <span class="n">now</span> <span class="o">=</span> <span class="p">{</span><span class="n">ID</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]]),</span> <span class="n">ID</span><span class="p">(</span><span class="n">A</span><span class="p">[</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="p">]]),</span> <span class="n">ID</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="n">c</span><span class="p">[</span><span class="n">i</span><span class="p">]]),</span> <span class="n">ID</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">3</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="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="n">j</span> <span class="o">:</span> <span class="n">now</span><span class="p">)</span> <span class="n">bit</span> <span class="o">|=</span> <span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">j</span><span class="p">,</span> <span class="n">ret</span> <span class="o">|=</span> <span class="n">j</span><span class="p">,</span> <span class="n">ret</span> <span class="o">&lt;&lt;=</span> <span class="mi">2</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">bit</span> <span class="o">!=</span> <span class="mi">15</span><span class="p">)</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="n">ret</span> <span class="o">|=</span> <span class="n">top</span><span class="p">;</span> <span class="k">return</span> <span class="n">Norm</span><span class="p">(</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">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">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">4</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">vector</span><span class="o">&lt;</span><span class="n">ll</span><span class="o">&gt;</span> <span class="n">res</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">a</span> <span class="o">:</span> <span class="n">fst</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">b</span> <span class="o">:</span> <span class="n">mp</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">c</span> <span class="o">:</span> <span class="n">mp</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">d</span> <span class="o">:</span> <span class="n">mp</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">Check</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">y</span><span class="p">,</span> <span class="n">c</span><span class="p">.</span><span class="n">y</span><span class="p">,</span> <span class="n">d</span><span class="p">.</span><span class="n">y</span><span class="p">,</span> <span class="n">ID</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="n">d</span><span class="p">.</span><span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">]])));</span> <span class="n">sort</span><span class="p">(</span><span class="n">all</span><span class="p">(</span><span class="n">res</span><span class="p">),</span> <span class="n">greater</span><span class="o">&lt;&gt;</span><span class="p">());</span> <span class="k">while</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">&amp;&amp;</span> <span class="o">!</span><span class="n">res</span><span class="p">.</span><span class="n">back</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">compress</span><span class="p">(</span><span class="n">res</span><span class="p">);</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">res</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="p">}</span> </code></pre></div></div>JusticeHui문제 링크 http://icpc.me/2598백준17823 수열과 쿼리 332021-04-05T05:40:00+00:002021-04-05T05:40:00+00:00https://justicehui.github.io/ps/2021/04/05/BOJ17823<h3 id="문제-링크">문제 링크</h3> <ul> <li>http://icpc.me/17823</li> </ul> <h3 id="사용-알고리즘">사용 알고리즘</h3> <ul> <li>Aliens Trick</li> <li>Parallel Binary Search</li> </ul> <h3 id="시간복잡도">시간복잡도</h3> <ul> <li>$O(N \log N \log X)$</li> </ul> <h3 id="풀이">풀이</h3> <p>구간의 양끝 원소의 사용 여부를 고정합시다. 각 구간의 양끝 원소의 사용 여부는 0부터 3까지의 정수로 인코딩할 수 있습니다. 또한, 구간의 양끝 사용 여부를 고정한 뒤 그래프를 잘 모델링하면 MCMF로 각 쿼리를 해결할 수 있습니다.</p> <p>“구간 $[l, r]$의 양끝 사용 여부가 $bit$일 때 $k$개의 부분 수열의 합의 최댓값”을 $f(l, r, bit, k)$로 정의하면, MCMF로 문제를 해결할 수 있기 때문에 $f(l,r,bit,k)-f(l,r,bit,k-1) \geq f(l,r,bit,k+1)-f(l,r,bit,k)$가 성립해서 Aliens Trick을 적용할 수 있다는 것을 알 수 있습니다.</p> <p>쿼리가 여러 개 주어지기 때문에 Parallel Binary Search를 생각해봅시다. PBS에서 우리가 수행해야 하는 연산은, “부분 수열 하나를 사용할 때 추가되는 비용이 $C$일 때 최적값”을 구하는 연산입니다.</p> <p>각 정점에서 구간 $[l, r]$의 $f(l, r, bit, 1), f(l, r, bit, 2), \cdots , f(l, r, bit, r-l+1)$을 관리하는 세그먼트 트리를 만듭시다. 만약 이러한 세그먼트 트리를 전처리했다면, PBS의 각 결정 문제는 쿼리로 주어진 구간을 나타내는 $O(\log N)$개의 정점에 저장된 함수들을 보며 해결할 수 있습니다.<br />이 세그먼트 트리는 $O(N \log N)$에 만들 수 있습니다. 두 구간 $[l, m], [m+1, r]$을 합치는 것이 병목이 될텐데, 이 부분은 두 볼록 함수의 민코프스키 합($R_{i+j} = \max(A_i + B_j)$)를 계산하는 것이기 때문에 선형 시간에 합칠 수 있습니다. 그러므로 세그먼트 트리를 전처리하는 시간 복잡도는 $T(N) = 2T(N/2) + O(N) = O(N \log N)$이 됩니다. 다만, $m$과 $m+1$을 <strong>모두 사용하는 경우</strong>에는 두 구간을 concat해주면 사용하는 부분 수열의 개수가 한 개 감소하기 때문에 배열을 왼쪽으로 한 칸 shift 해야합니다.</p> <p>이제 PBS를 합시다. 구간 개수 $k$와 추가 비용 $C$에 대해, $kC + f(k)$ 꼴의 최댓값을 계산하는 작업을 수행해야 하고, 이는 Convex Hull Trick과 매우 유사합니다. 심지어 세그먼트 트리의 각 정점에는 이미 <strong>볼록 함수</strong>가 저장되어 있기 때문에, 그냥 쿼리에 달려있는 $C$를 다 모아서 정렬한 뒤 선형 CHT 느낌으로 계산하면 됩니다.</p> <p>PBS의 각 iteration마다 $O(N \log N)$ 시간이 걸리므로 전체 시간 복잡도는 $O(N \log N \log X)$가 됩니다. 물론, 다양한 bit의 조합을 계산해야 하기 때문에 세그먼트 트리를 전처리하는 과정과 PBS의 iteration에서 상수가 8 정도 더 붙습니다.</p> <h3 id="전체-코드">전체 코드</h3> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/****************************** Author: jhnah917(Justice_Hui) g++ -std=c++17 -DLOCAL ******************************/</span> <span class="cp">#include &lt;bits/stdc++.h&gt; #define x first #define y second #define all(v) v.begin(), v.end() #define compress(v) sort(all(v)), v.erase(unique(all(v)), v.end()) #define IDX(v, x) (lower_bound(all(v), x) - v.begin()) </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">uint</span> <span class="o">=</span> <span class="kt">unsigned</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">ull</span> <span class="o">=</span> <span class="kt">unsigned</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">16</span><span class="p">;</span> <span class="k">constexpr</span> <span class="kt">int</span> <span class="n">INF32</span> <span class="o">=</span> <span class="mh">0x3f3f3f3f</span><span class="p">;</span> <span class="k">constexpr</span> <span class="n">ll</span> <span class="n">INF</span> <span class="o">=</span> <span class="mh">0x3f3f3f3f3f3f3f3f</span><span class="p">;</span> <span class="n">PLL</span> <span class="k">operator</span> <span class="o">+</span> <span class="p">(</span><span class="k">const</span> <span class="n">PLL</span> <span class="o">&amp;</span><span class="n">p1</span><span class="p">,</span> <span class="k">const</span> <span class="n">PLL</span> <span class="o">&amp;</span><span class="n">p2</span><span class="p">){</span> <span class="k">return</span> <span class="p">{</span><span class="n">p1</span><span class="p">.</span><span class="n">x</span> <span class="o">+</span> <span class="n">p2</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">p1</span><span class="p">.</span><span class="n">y</span> <span class="o">+</span> <span class="n">p2</span><span class="p">.</span><span class="n">y</span><span class="p">};</span> <span class="p">}</span> <span class="n">PLL</span> <span class="k">operator</span> <span class="o">-</span> <span class="p">(</span><span class="k">const</span> <span class="n">PLL</span> <span class="o">&amp;</span><span class="n">p1</span><span class="p">,</span> <span class="k">const</span> <span class="n">PLL</span> <span class="o">&amp;</span><span class="n">p2</span><span class="p">){</span> <span class="k">return</span> <span class="p">{</span><span class="n">p1</span><span class="p">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">p2</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">p1</span><span class="p">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">p2</span><span class="p">.</span><span class="n">y</span><span class="p">};</span> <span class="p">}</span> <span class="k">struct</span> <span class="nc">Node</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="n">ll</span><span class="o">&gt;</span> <span class="n">V</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">2</span><span class="p">];</span> <span class="n">Node</span><span class="p">()</span> <span class="o">:</span> <span class="n">Node</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">{}</span> <span class="n">Node</span><span class="p">(</span><span class="kt">int</span> <span class="n">sz</span><span class="p">)</span> <span class="o">:</span> <span class="n">sz</span><span class="p">(</span><span class="n">sz</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">i</span><span class="o">&lt;</span><span class="mi">2</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="mi">2</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="n">V</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">ll</span><span class="o">&gt;</span><span class="p">(</span><span class="n">sz</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="n">INF</span><span class="p">);</span> <span class="p">}</span> <span class="kt">int</span> <span class="n">size</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">sz</span><span class="p">;</span> <span class="p">}</span> <span class="kt">void</span> <span class="n">reset</span><span class="p">(</span><span class="kt">int</span> <span class="n">_sz</span><span class="p">){</span> <span class="n">sz</span> <span class="o">=</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="mi">2</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="mi">2</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="n">V</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">ll</span><span class="o">&gt;</span><span class="p">(</span><span class="n">sz</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="n">INF</span><span class="p">);</span> <span class="p">}</span> <span class="kt">void</span> <span class="n">setValue</span><span class="p">(</span><span class="n">ll</span> <span class="n">v</span><span class="p">){</span> <span class="n">reset</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">2</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="mi">2</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="n">V</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</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="o">?</span> <span class="o">-</span><span class="n">INF</span> <span class="o">:</span> <span class="mi">0</span><span class="p">;</span> <span class="n">V</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="p">};</span> <span class="n">Node</span> <span class="k">operator</span> <span class="o">+</span> <span class="p">(</span><span class="k">const</span> <span class="n">Node</span> <span class="o">&amp;</span><span class="n">A</span><span class="p">,</span> <span class="k">const</span> <span class="n">Node</span> <span class="o">&amp;</span><span class="n">B</span><span class="p">){</span> <span class="k">static</span> <span class="k">auto</span> <span class="n">dx</span> <span class="o">=</span> <span class="p">[](</span><span class="k">const</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">ll</span><span class="o">&gt;</span> <span class="o">&amp;</span><span class="n">vec</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">ret</span><span class="p">;</span> <span class="n">ret</span><span class="p">.</span><span class="n">reserve</span><span class="p">(</span><span class="n">vec</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">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">vec</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">ret</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">vec</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">-</span> <span class="n">vec</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">return</span> <span class="n">move</span><span class="p">(</span><span class="n">ret</span><span class="p">);</span> <span class="p">};</span> <span class="n">Node</span> <span class="n">R</span><span class="p">(</span><span class="n">A</span><span class="p">.</span><span class="n">size</span><span class="p">()</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="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">2</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="mi">2</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="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="mi">2</span><span class="p">;</span> <span class="n">k</span><span class="o">++</span><span class="p">){</span> <span class="k">auto</span> <span class="n">da</span> <span class="o">=</span> <span class="n">dx</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">i</span><span class="p">][</span><span class="n">j</span><span class="p">]),</span> <span class="n">db</span> <span class="o">=</span> <span class="n">dx</span><span class="p">(</span><span class="n">B</span><span class="p">.</span><span class="n">V</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">k</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">res</span><span class="p">(</span><span class="n">da</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">+</span> <span class="n">db</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">res</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">A</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">j</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">B</span><span class="p">.</span><span class="n">V</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="mi">0</span><span class="p">];</span> <span class="n">merge</span><span class="p">(</span><span class="n">all</span><span class="p">(</span><span class="n">da</span><span class="p">),</span> <span class="n">all</span><span class="p">(</span><span class="n">db</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="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">greater</span><span class="o">&lt;&gt;</span><span class="p">());</span> <span class="n">partial_sum</span><span class="p">(</span><span class="n">all</span><span class="p">(</span><span class="n">res</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="k">if</span><span class="p">(</span><span class="n">j</span><span class="p">)</span> <span class="n">res</span><span class="p">.</span><span class="n">erase</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="k">for</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="n">s</span><span class="o">&lt;</span><span class="n">res</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">s</span><span class="o">++</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">i</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="n">s</span><span class="p">]</span> <span class="o">=</span> <span class="n">max</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">i</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="n">s</span><span class="p">],</span> <span class="n">res</span><span class="p">[</span><span class="n">s</span><span class="p">]);</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="k">return</span> <span class="n">R</span><span class="p">;</span> <span class="p">}</span> <span class="k">constexpr</span> <span class="n">PLL</span> <span class="n">BASE</span> <span class="o">=</span> <span class="n">PLL</span><span class="p">(</span><span class="o">-</span><span class="n">INF</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="k">struct</span> <span class="nc">Info</span><span class="p">{</span> <span class="n">PLL</span> <span class="n">V</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">2</span><span class="p">];</span> <span class="n">Info</span><span class="p">()</span> <span class="o">:</span> <span class="n">Info</span><span class="p">(</span><span class="n">BASE</span><span class="p">,</span> <span class="n">BASE</span><span class="p">,</span> <span class="n">BASE</span><span class="p">,</span> <span class="n">BASE</span><span class="p">)</span> <span class="p">{}</span> <span class="n">Info</span><span class="p">(</span><span class="n">PLL</span> <span class="n">a</span><span class="p">,</span> <span class="n">PLL</span> <span class="n">b</span><span class="p">,</span> <span class="n">PLL</span> <span class="n">c</span><span class="p">,</span> <span class="n">PLL</span> <span class="n">d</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="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">a</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="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">b</span><span class="p">;</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">c</span><span class="p">;</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">d</span><span class="p">;</span> <span class="p">}</span> <span class="n">PLL</span> <span class="n">max</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">max</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="mi">0</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="mi">1</span><span class="p">],</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">0</span><span class="p">],</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">1</span><span class="p">]});</span> <span class="p">}</span> <span class="p">};</span> <span class="n">Info</span> <span class="nf">Merge</span><span class="p">(</span><span class="k">const</span> <span class="n">Info</span> <span class="o">&amp;</span><span class="n">A</span><span class="p">,</span> <span class="k">const</span> <span class="n">Info</span> <span class="o">&amp;</span><span class="n">B</span><span class="p">,</span> <span class="k">const</span> <span class="n">ll</span> <span class="n">lambda</span><span class="p">){</span> <span class="n">Info</span> <span class="n">R</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">2</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="mi">2</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="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="mi">2</span><span class="p">;</span> <span class="n">k</span><span class="o">++</span><span class="p">){</span> <span class="n">PLL</span> <span class="n">now</span> <span class="o">=</span> <span class="n">A</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">j</span><span class="p">]</span> <span class="o">+</span> <span class="n">B</span><span class="p">.</span><span class="n">V</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">k</span><span class="p">];</span> <span class="k">if</span><span class="p">(</span><span class="n">j</span><span class="p">)</span> <span class="n">now</span> <span class="o">=</span> <span class="n">now</span> <span class="o">-</span> <span class="n">PLL</span><span class="p">(</span><span class="n">lambda</span><span class="p">,</span> <span class="mi">1</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">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">R</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">k</span><span class="p">],</span> <span class="n">now</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="k">return</span> <span class="n">R</span><span class="p">;</span> <span class="p">}</span> <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">A</span><span class="p">[</span><span class="n">SZ</span><span class="p">];</span> <span class="n">ll</span> <span class="n">S</span><span class="p">[</span><span class="n">SZ</span><span class="p">],</span> <span class="n">E</span><span class="p">[</span><span class="n">SZ</span><span class="p">],</span> <span class="n">K</span><span class="p">[</span><span class="n">SZ</span><span class="p">],</span> <span class="n">L</span><span class="p">[</span><span class="n">SZ</span><span class="p">],</span> <span class="n">R</span><span class="p">[</span><span class="n">SZ</span><span class="p">],</span> <span class="n">M</span><span class="p">[</span><span class="n">SZ</span><span class="p">];</span> <span class="n">Info</span> <span class="n">X</span><span class="p">[</span><span class="n">SZ</span><span class="p">];</span> <span class="n">Node</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="kt">int</span> <span class="n">pv</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="mi">2</span><span class="p">][</span><span class="mi">2</span><span class="p">];</span> <span class="c1">// for CHT</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">nds</span><span class="p">[</span><span class="n">SZ</span><span class="p">];</span> <span class="kt">void</span> <span class="nf">Init</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="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="n">setValue</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">s</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="n">s</span> <span class="o">+</span> <span class="n">e</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span> <span class="n">Init</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">Init</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">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="o">+</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">Insert</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="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">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">nds</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">node</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="n">s</span> <span class="o">+</span> <span class="n">e</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span> <span class="n">Insert</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">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">Insert</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">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="p">}</span> <span class="n">PLL</span> <span class="nf">CHT</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">i</span><span class="p">,</span> <span class="kt">int</span> <span class="n">j</span><span class="p">,</span> <span class="kt">int</span> <span class="n">q</span><span class="p">){</span> <span class="k">auto</span> <span class="o">&amp;</span><span class="n">hull</span> <span class="o">=</span> <span class="n">T</span><span class="p">[</span><span class="n">node</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">j</span><span class="p">];</span> <span class="k">auto</span> <span class="o">&amp;</span><span class="n">cnt</span> <span class="o">=</span> <span class="n">pv</span><span class="p">[</span><span class="n">node</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">];</span> <span class="k">while</span><span class="p">(</span><span class="n">cnt</span><span class="o">+</span><span class="mi">1</span> <span class="o">&lt;</span> <span class="n">hull</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">hull</span><span class="p">[</span><span class="n">cnt</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">hull</span><span class="p">[</span><span class="n">cnt</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">M</span><span class="p">[</span><span class="n">q</span><span class="p">])</span> <span class="n">cnt</span><span class="o">++</span><span class="p">;</span> <span class="n">ll</span> <span class="n">dp</span> <span class="o">=</span> <span class="n">hull</span><span class="p">[</span><span class="n">cnt</span><span class="p">]</span> <span class="o">+</span> <span class="n">M</span><span class="p">[</span><span class="n">q</span><span class="p">]</span> <span class="o">*</span> <span class="n">cnt</span><span class="p">;</span> <span class="k">return</span> <span class="n">PLL</span><span class="p">(</span><span class="n">dp</span><span class="p">,</span> <span class="n">cnt</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="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">Init</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="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">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">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&gt;&gt;</span> <span class="n">E</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&gt;&gt;</span> <span class="n">K</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">Insert</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="n">N</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">E</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="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">L</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">INF32</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">INF32</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">Q</span><span class="p">);</span> <span class="n">iota</span><span class="p">(</span><span class="n">all</span><span class="p">(</span><span class="n">O</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="nb">true</span><span class="p">){</span> <span class="kt">bool</span> <span class="n">fin</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="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="k">if</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="p">])</span> <span class="n">fin</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span> <span class="k">if</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="p">]</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="n">M</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">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="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">else</span> <span class="n">M</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">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="p">])</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span> <span class="p">}</span> <span class="n">memset</span><span class="p">(</span><span class="n">pv</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span> <span class="n">pv</span><span class="p">);</span> <span class="n">sort</span><span class="p">(</span><span class="n">all</span><span class="p">(</span><span class="n">O</span><span class="p">),</span> <span class="p">[</span><span class="o">&amp;</span><span class="p">](</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">){</span> <span class="k">return</span> <span class="n">M</span><span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">M</span><span class="p">[</span><span class="n">b</span><span class="p">];</span> <span class="p">});</span> <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="n">q</span> <span class="o">:</span> <span class="n">O</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="n">nd</span> <span class="o">:</span> <span class="n">nds</span><span class="p">[</span><span class="n">q</span><span class="p">]){</span> <span class="n">Info</span> <span class="n">now</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">2</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;</span><span class="mi">2</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span> <span class="n">now</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">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">CHT</span><span class="p">(</span><span class="n">nd</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">q</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">flag</span><span class="p">)</span> <span class="n">X</span><span class="p">[</span><span class="n">q</span><span class="p">]</span> <span class="o">=</span> <span class="n">now</span><span class="p">;</span> <span class="k">else</span> <span class="n">X</span><span class="p">[</span><span class="n">q</span><span class="p">]</span> <span class="o">=</span> <span class="n">Merge</span><span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="n">q</span><span class="p">],</span> <span class="n">now</span><span class="p">,</span> <span class="n">M</span><span class="p">[</span><span class="n">q</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="p">}</span> <span class="k">if</span><span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="n">q</span><span class="p">].</span><span class="n">max</span><span class="p">().</span><span class="n">y</span> <span class="o">&gt;=</span> <span class="n">K</span><span class="p">[</span><span class="n">q</span><span class="p">])</span> <span class="n">R</span><span class="p">[</span><span class="n">q</span><span class="p">]</span> <span class="o">=</span> <span class="n">M</span><span class="p">[</span><span class="n">q</span><span class="p">];</span> <span class="k">else</span> <span class="n">L</span><span class="p">[</span><span class="n">q</span><span class="p">]</span> <span class="o">=</span> <span class="n">M</span><span class="p">[</span><span class="n">q</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">if</span><span class="p">(</span><span class="n">fin</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">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">X</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">max</span><span class="p">().</span><span class="n">x</span> <span class="o">-</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">L</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> <span class="p">}</span> </code></pre></div></div>JusticeHui문제 링크 http://icpc.me/17823백준17518 Wind of Change2021-04-04T05:20:00+00:002021-04-04T05:20:00+00:00https://justicehui.github.io/ps/2021/04/04/BOJ17518<h3 id="문제-링크">문제 링크</h3> <ul> <li>http://icpc.me/17518</li> </ul> <h3 id="사용-알고리즘">사용 알고리즘</h3> <ul> <li>Centroid Decomposition</li> </ul> <h3 id="시간복잡도">시간복잡도</h3> <ul> <li>$O(N \log^2 N)$</li> </ul> <h3 id="풀이">풀이</h3> <p>루비 5 문제를 푸는 사람이라면 모두가 알고 있을 사실 2가지를 짚고 넘어가겠습니다.</p> <ul> <li>트리 $T$의 정점 $i$에서 $j$로 가는 경로의 거리 $D(i, j)$는 $T$의 Centroid Tree $C_T$에서 $i, j$의 LCA $L = LCA_{C_T}(i, j)$에 대해 $D(L, i) + D(L, j)$입니다.</li> <li>$D(i, j)$는 $T$의 Centroid Tree $C_T$에서 $i, j$의 공통 조상 $P$에 대해 $D(i, j) \leq D(P, i) + D(P, j)$를 만족합니다.</li> </ul> <p>이 두 사실을 잘 기억하고 있으면 풀이는 상당히 쉽게 나옵니다.</p> <p>$T_1, T_2$의 Centroid Tree $C_{T_1}, C_{T_2}$를 만듭시다. $C_{T_1}$에서 어떤 정점 $v$를 루트로 하는 서브 트리 내에서의 정답을 모두 구하는 방법을 알아봅시다.<br />서브 트리 내에서 $v$의 자손 $c$의 정답은, 서브 트리 내에 있는 또 다른 정점 $x$에 대해 $D_1(c, v) + D_1(v, x) + D_2(v, x)$ 이하가 됩니다. 만약 $C_{T_2}$에서 $x$의 모든 조상 $y$를 순회한다면 $D_1(c, v) + D_1(v, x) + D_2(v, y) + D_2(y, x)$를 계산해도 됩니다.<br />그러므로 $C_{T_1}$에서 $v$의 자손 $x$에 대해 $C_{T_2}$에서 $x$의 조상 $y$에 $D_1(v, x) + D_2(y, x)$의 최솟값을 저장한 뒤, 다시 $C_{T_1}$에서 $v$의 자손 $c$마다 $C_{T_2}$에서 $c$의 조상 $p$를 순회하면서 정답을 갱신하면 됩니다. (($p$에 저장된 최솟값)$+ D_1(c, v) + D_2(p, c)$ 갱신)</p> <p>$C_{T_1}$에서 $v$를 루트로 하는 서브 트리의 크기를 $S_v$라고 할 때, $v$의 서브 트리 내에서의 정답은 $O(S_v \log N)$ 시간에 구할 수 있습니다. Centroid Tree에서 $\sum S_v \in O(N \log N)$이므로 $O(N \log^2 N)$에 문제를 풀 수 있습니다.</p> <h3 id="전체-코드">전체 코드</h3> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/****************************** Author: jhnah917(Justice_Hui) g++ -std=c++17 -DLOCAL ******************************/</span> <span class="cp">#include &lt;bits/stdc++.h&gt; #define x first #define y second #define all(v) v.begin(), v.end() #define compress(v) sort(all(v)), v.erase(unique(all(v)), v.end()) #define IDX(v, x) (lower_bound(all(v), x) - v.begin()) </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">uint</span> <span class="o">=</span> <span class="kt">unsigned</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">ull</span> <span class="o">=</span> <span class="kt">unsigned</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="n">ll</span> <span class="n">SZ</span> <span class="o">=</span> <span class="mi">252525</span><span class="p">,</span> <span class="n">INF</span> <span class="o">=</span> <span class="mh">0x3f3f3f3f3f3f3f3f</span><span class="p">;</span> <span class="k">struct</span> <span class="nc">MinPair</span><span class="p">{</span> <span class="n">PLL</span> <span class="n">V</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span> <span class="n">MinPair</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="o">=</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">PLL</span><span class="p">(</span><span class="n">INF</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="n">clear</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="o">=</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">PLL</span><span class="p">(</span><span class="n">INF</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="n">update</span><span class="p">(</span><span class="k">const</span> <span class="n">PLL</span> <span class="n">v</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="o">&gt;</span> <span class="n">v</span><span class="p">)</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</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">0</span><span class="p">]</span> <span class="o">=</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">V</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">v</span><span class="p">)</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span><span class="p">;</span> <span class="p">}</span> <span class="k">const</span> <span class="n">PLL</span><span class="o">&amp;</span> <span class="k">operator</span> <span class="p">[]</span> <span class="p">(</span><span class="kt">int</span> <span class="n">idx</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">V</span><span class="p">[</span><span class="n">idx</span><span class="p">];</span> <span class="p">}</span> <span class="p">};</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">S</span><span class="p">[</span><span class="n">SZ</span><span class="p">],</span> <span class="n">U</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="n">PLL</span><span class="o">&gt;</span> <span class="n">G</span><span class="p">[</span><span class="mi">2</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="n">PLL</span><span class="o">&gt;</span> <span class="n">cInfo</span><span class="p">[</span><span class="n">SZ</span><span class="p">],</span> <span class="n">pInfo</span><span class="p">[</span><span class="n">SZ</span><span class="p">];</span> <span class="n">MinPair</span> <span class="n">Small</span><span class="p">[</span><span class="n">SZ</span><span class="p">];</span> <span class="n">ll</span> <span class="n">R</span><span class="p">[</span><span class="n">SZ</span><span class="p">];</span> <span class="kt">void</span> <span class="nf">add_edge</span><span class="p">(</span><span class="kt">int</span> <span class="n">id</span><span class="p">,</span> <span class="kt">int</span> <span class="n">s</span><span class="p">,</span> <span class="kt">int</span> <span class="n">e</span><span class="p">,</span> <span class="kt">int</span> <span class="n">x</span><span class="p">){</span> <span class="n">G</span><span class="p">[</span><span class="n">id</span><span class="p">][</span><span class="n">s</span><span class="p">].</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">x</span><span class="p">);</span> <span class="n">G</span><span class="p">[</span><span class="n">id</span><span class="p">][</span><span class="n">e</span><span class="p">].</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">x</span><span class="p">);</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">get_sz</span><span class="p">(</span><span class="kt">int</span> <span class="n">id</span><span class="p">,</span> <span class="kt">int</span> <span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</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="n">i</span> <span class="o">:</span> <span class="n">G</span><span class="p">[</span><span class="n">id</span><span class="p">][</span><span class="n">v</span><span class="p">])</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">U</span><span class="p">[</span><span class="n">i</span><span class="p">.</span><span class="n">x</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="n">i</span><span class="p">.</span><span class="n">x</span> <span class="o">!=</span> <span class="n">b</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">get_sz</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="n">x</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">get_cent</span><span class="p">(</span><span class="kt">int</span> <span class="n">id</span><span class="p">,</span> <span class="kt">int</span> <span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">tot</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</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">id</span><span class="p">][</span><span class="n">v</span><span class="p">])</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">U</span><span class="p">[</span><span class="n">i</span><span class="p">.</span><span class="n">x</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="n">i</span><span class="p">.</span><span class="n">x</span> <span class="o">!=</span> <span class="n">b</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="n">x</span><span class="p">]</span><span class="o">*</span><span class="mi">2</span> <span class="o">&gt;</span> <span class="n">tot</span><span class="p">)</span> <span class="k">return</span> <span class="n">get_cent</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="n">x</span><span class="p">,</span> <span class="n">tot</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">gather</span><span class="p">(</span><span class="kt">int</span> <span class="n">id</span><span class="p">,</span> <span class="kt">int</span> <span class="n">rt</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="kt">int</span> <span class="n">d</span><span class="p">,</span> <span class="n">ll</span> <span class="n">c</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">id</span><span class="p">)</span> <span class="n">cInfo</span><span class="p">[</span><span class="n">rt</span><span class="p">].</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">c</span><span class="p">);</span> <span class="k">else</span> <span class="n">pInfo</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">rt</span><span class="p">,</span> <span class="n">c</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">id</span><span class="p">][</span><span class="n">v</span><span class="p">])</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">U</span><span class="p">[</span><span class="n">i</span><span class="p">.</span><span class="n">x</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="n">i</span><span class="p">.</span><span class="n">x</span> <span class="o">!=</span> <span class="n">b</span><span class="p">)</span> <span class="n">gather</span><span class="p">(</span><span class="n">id</span><span class="p">,</span> <span class="n">rt</span><span class="p">,</span> <span class="n">i</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">d</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">c</span><span class="o">+</span><span class="n">i</span><span class="p">.</span><span class="n">y</span><span class="p">);</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">cd</span><span class="p">(</span><span class="kt">int</span> <span class="n">id</span><span class="p">,</span> <span class="kt">int</span> <span class="n">v</span><span class="p">){</span> <span class="kt">int</span> <span class="n">cent</span> <span class="o">=</span> <span class="n">get_cent</span><span class="p">(</span><span class="n">id</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">get_sz</span><span class="p">(</span><span class="n">id</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="o">-</span><span class="mi">1</span><span class="p">);</span> <span class="n">gather</span><span class="p">(</span><span class="n">id</span><span class="p">,</span> <span class="n">cent</span><span class="p">,</span> <span class="n">cent</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="n">U</span><span class="p">[</span><span class="n">cent</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="n">i</span> <span class="o">:</span> <span class="n">G</span><span class="p">[</span><span class="n">id</span><span class="p">][</span><span class="n">cent</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">x</span><span class="p">])</span> <span class="n">cd</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="n">x</span><span class="p">);</span> <span class="n">U</span><span class="p">[</span><span class="n">cent</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">Go</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="k">auto</span> <span class="n">i</span> <span class="o">:</span> <span class="n">cInfo</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="n">j</span> <span class="o">:</span> <span class="n">pInfo</span><span class="p">[</span><span class="n">i</span><span class="p">.</span><span class="n">x</span><span class="p">])</span> <span class="n">Small</span><span class="p">[</span><span class="n">j</span><span class="p">.</span><span class="n">x</span><span class="p">].</span><span class="n">clear</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">cInfo</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="n">j</span> <span class="o">:</span> <span class="n">pInfo</span><span class="p">[</span><span class="n">i</span><span class="p">.</span><span class="n">x</span><span class="p">])</span> <span class="n">Small</span><span class="p">[</span><span class="n">j</span><span class="p">.</span><span class="n">x</span><span class="p">].</span><span class="n">update</span><span class="p">({</span><span class="n">i</span><span class="p">.</span><span class="n">y</span><span class="o">+</span><span class="n">j</span><span class="p">.</span><span class="n">y</span><span class="p">,</span> <span class="n">i</span><span class="p">.</span><span class="n">x</span><span class="p">});</span> <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="n">i</span> <span class="o">:</span> <span class="n">cInfo</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="n">j</span> <span class="o">:</span> <span class="n">pInfo</span><span class="p">[</span><span class="n">i</span><span class="p">.</span><span class="n">x</span><span class="p">])</span> <span class="p">{</span> <span class="k">if</span><span class="p">(</span><span class="n">Small</span><span class="p">[</span><span class="n">j</span><span class="p">.</span><span class="n">x</span><span class="p">][</span><span class="mi">0</span><span class="p">].</span><span class="n">y</span> <span class="o">!=</span> <span class="n">i</span><span class="p">.</span><span class="n">x</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">x</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="p">[</span><span class="n">i</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="n">y</span> <span class="o">+</span> <span class="n">j</span><span class="p">.</span><span class="n">y</span> <span class="o">+</span> <span class="n">Small</span><span class="p">[</span><span class="n">j</span><span class="p">.</span><span class="n">x</span><span class="p">][</span><span class="mi">0</span><span class="p">].</span><span class="n">x</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="n">Small</span><span class="p">[</span><span class="n">j</span><span class="p">.</span><span class="n">x</span><span class="p">][</span><span class="mi">1</span><span class="p">].</span><span class="n">y</span> <span class="o">!=</span> <span class="n">i</span><span class="p">.</span><span class="n">x</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">x</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="p">[</span><span class="n">i</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="n">y</span> <span class="o">+</span> <span class="n">j</span><span class="p">.</span><span class="n">y</span> <span class="o">+</span> <span class="n">Small</span><span class="p">[</span><span class="n">j</span><span class="p">.</span><span class="n">x</span><span class="p">][</span><span class="mi">1</span><span class="p">].</span><span class="n">x</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">ios_base</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">N</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="n">s</span><span class="p">,</span><span class="n">e</span><span class="p">,</span><span class="n">x</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">s</span> <span class="o">&gt;&gt;</span> <span class="n">e</span> <span class="o">&gt;&gt;</span> <span class="n">x</span><span class="p">,</span> <span class="n">add_edge</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">e</span><span class="p">,</span> <span class="n">x</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">s</span><span class="p">,</span><span class="n">e</span><span class="p">,</span><span class="n">x</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">s</span> <span class="o">&gt;&gt;</span> <span class="n">e</span> <span class="o">&gt;&gt;</span> <span class="n">x</span><span class="p">,</span> <span class="n">add_edge</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">e</span><span class="p">,</span> <span class="n">x</span><span class="p">);</span> <span class="n">cd</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">cd</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="n">memset</span><span class="p">(</span><span class="n">R</span><span class="p">,</span> <span class="mh">0x3f</span><span class="p">,</span> <span class="k">sizeof</span> <span class="n">R</span><span class="p">);</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</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="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">R</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div>JusticeHui문제 링크 http://icpc.me/17518