<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>aram_father.log</title>
        <link>https://velog.io/</link>
        <description>Pseudo-worker</description>
        <lastBuildDate>Sun, 03 Apr 2022 13:26:52 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>aram_father.log</title>
            <url>https://images.velog.io/images/aram_father/profile/99448630-bf11-40d9-9ad7-3cc79b28346a/이원석_프로필사진.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. aram_father.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/aram_father" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[불 끄기]]></title>
            <link>https://velog.io/@aram_father/%EB%B6%88-%EB%81%84%EA%B8%B0</link>
            <guid>https://velog.io/@aram_father/%EB%B6%88-%EB%81%84%EA%B8%B0</guid>
            <pubDate>Sun, 03 Apr 2022 13:26:52 GMT</pubDate>
            <description><![CDATA[<p><strong>Problme link:</strong> <a href="https://www.acmicpc.net/problem/14939">https://www.acmicpc.net/problem/14939</a></p>
<p>행 단위로 각 행에 있는 전구를 누를지 말지 결정한다고 해보자.</p>
<p><code>i</code>번쨰 행의 <code>j</code>번째 열에 위치하는 전구를 고려할 때, 사실 얘를 누를지 말지는 <code>i-1</code>행 <code>j</code>열의 전구가 결정한다.</p>
<p>문제의 특성상 만약 윗 행의 전구가 켜져 있다면 누르지 않고서는 얘를 꺼줄 방법이 없기 때문이다.</p>
<p>따라서, 첫 행만 전 탐색해주고 나머지 행은 그리디로 진행해주면 된다.</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;

using namespace std;

class Bulbs
{
private:
  size_t num_of_on_bulbs_;
  vector&lt;string&gt; bulbs_;

public:
  Bulbs(const vector&lt;string&gt;&amp; bulbs) : num_of_on_bulbs_(0), bulbs_(bulbs)
  {
    for (int r = 0; r &lt; 10; ++r)
    {
      for (int c = 0; c &lt; 10; ++c)
      {
        if (bulbs[r][c] == &#39;O&#39;)
        {
          ++num_of_on_bulbs_;
        }
      }
    }
  }

  vector&lt;string&gt;&amp; bulbs()
  {
    return bulbs_;
  }

  size_t num_of_on_bulbs() const
  {
    return num_of_on_bulbs_;
  }

  void Push(const int r, const int c)
  {
    const int dr[5] = { 0, -1, 0, 1, 0 };
    const int dc[5] = { 0, 0, 1, 0, -1 };

    for (int d = 0; d &lt; 5; ++d)
    {
      int nr = r + dr[d];
      int nc = c + dc[d];

      if (0 &lt;= nr &amp;&amp; nr &lt; 10 &amp;&amp; 0 &lt;= nc &amp;&amp; nc &lt; 10)
      {
        switch (bulbs_[nr][nc])
        {
          case &#39;O&#39;:
            bulbs_[nr][nc] = &#39;#&#39;;
            --num_of_on_bulbs_;
            break;
          case &#39;#&#39;:
            bulbs_[nr][nc] = &#39;O&#39;;
            ++num_of_on_bulbs_;
            break;
        }
      }
    }
  }
};

vector&lt;string&gt; BULBS(10, &quot;&quot;);

int Solve()
{
  int answer = 10 * 10 + 1;

  for (int first_row_mask = 0; first_row_mask &lt; (1 &lt;&lt; 10); ++first_row_mask)
  {
    Bulbs bulbs(BULBS);

    int num_of_pushes = 0;

    // Process first row
    for (int col = 0; col &lt; 10; ++col)
    {
      if (first_row_mask &amp; (1 &lt;&lt; col))
      {
        bulbs.Push(0, col);
        ++num_of_pushes;
      }
    }

    // Process remaining rows
    for (int row = 1; row &lt; 10; ++row)
    {
      for (int col = 0; col &lt; 10; ++col)
      {
        if (bulbs.bulbs()[row - 1][col] == &#39;O&#39;)
        {
          bulbs.Push(row, col);
          ++num_of_pushes;
        }
      }
    }

    if (bulbs.num_of_on_bulbs() == 0)
    {
      answer = min(answer, num_of_pushes);
    }
  }

  return answer &gt; 100 ? -1 : answer;
}

int main(void)
{
  // Read input
  for (int row = 0; row &lt; 10; ++row)
  {
    cin &gt;&gt; BULBS[row];
  }

  // Sovle
  cout &lt;&lt; Solve() &lt;&lt; endl;

  return 0;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[가장 긴 증가하는 부분 수열 5]]></title>
            <link>https://velog.io/@aram_father/%EA%B0%80%EC%9E%A5-%EA%B8%B4-%EC%A6%9D%EA%B0%80%ED%95%98%EB%8A%94-%EB%B6%80%EB%B6%84-%EC%88%98%EC%97%B4-5</link>
            <guid>https://velog.io/@aram_father/%EA%B0%80%EC%9E%A5-%EA%B8%B4-%EC%A6%9D%EA%B0%80%ED%95%98%EB%8A%94-%EB%B6%80%EB%B6%84-%EC%88%98%EC%97%B4-5</guid>
            <pubDate>Sun, 03 Apr 2022 13:25:21 GMT</pubDate>
            <description><![CDATA[<p><strong>Problme link:</strong> <a href="https://www.acmicpc.net/problem/14003">https://www.acmicpc.net/problem/14003</a></p>
<p>별로 특별할 것 없이 lower_bound를 사용해서 풀어주면 LIS의 길이까지는 무리 없이 구해줄 수 있다.</p>
<p>여기서 실제 LIS를 재구성해내는데 조금 어려움을 겪었는데, 결과적으로는 아래의 방법을 사용하였다.</p>
<p>LIS를 풀면서 아래의 정보를 유지해준다.</p>
<ul>
<li><code>P[i]: A[i]가 LIS의 몇 번째 수로서 포함될 수 있었는가?</code></li>
</ul>
<p>LIS의 길이를 구한 뒤에 <code>P[i]</code>를 뒤에서부터 보면서 답을 재구성해주면 된다.</p>
<pre><code class="language-cpp">#include &lt;cstdio&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;

using namespace std;

const int kMaxN = 1000000;

int N;
int A[kMaxN];
int P[kMaxN];

vector&lt;int&gt; CACHE;
vector&lt;int&gt; LIS;

int main(void)
{
  // Read input
  scanf(&quot; %d&quot;, &amp;N);
  for (int i = 0; i &lt; N; ++i)
  {
    scanf(&quot; %d&quot;, &amp;A[i]);
  }

  // Get length
  for (int i = 0; i &lt; N; ++i)
  {
    auto it = lower_bound(CACHE.begin(), CACHE.end(), A[i]);
    if (it == CACHE.end())
    {
      CACHE.emplace_back(A[i]);
      P[i] = (int)CACHE.size() - 1;
    }
    else
    {
      *it = A[i];
      P[i] = (int)(it - CACHE.begin());
    }
  }

  // Print answer
  printf(&quot;%d\n&quot;, (int)CACHE.size());

  int target = (int)CACHE.size() - 1;
  for (int i = N - 1; i &gt;= 0 &amp;&amp; target &gt;= 0; --i)
  {
    if (P[i] == target)
    {
      LIS.emplace_back(A[i]);
      --target;
    }
  }

  for (auto r = LIS.rbegin(); r != LIS.rend(); ++r)
  {
    printf(&quot;%d &quot;, *r);
  }
  printf(&quot;\n&quot;);

  return 0;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[1로 만들기 2]]></title>
            <link>https://velog.io/@aram_father/1%EB%A1%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0-2</link>
            <guid>https://velog.io/@aram_father/1%EB%A1%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0-2</guid>
            <pubDate>Sun, 03 Apr 2022 13:24:08 GMT</pubDate>
            <description><![CDATA[<p><strong>Problme link:</strong> <a href="https://www.acmicpc.net/problem/12852">https://www.acmicpc.net/problem/12852</a></p>
<p>포인트 냠냠을 위한 BFS 문제이다.</p>
<p>숫자가 작아지면 작아지지 커질 수는 없다는 사실로부터 범위 내의 양수들만 접근하리라는 것을 알 수 있다.</p>
<pre><code class="language-cpp">#include &lt;cstdio&gt;
#include &lt;queue&gt;
#include &lt;vector&gt;

using namespace std;

int N;
int V[1000000 + 1];
int P[1000000 + 1];

void Bfs(const int start)
{
  V[start] = 1;
  P[start] = -1;

  queue&lt;int&gt; q;
  q.emplace(start);

  while (!q.empty())
  {
    int here = q.front();
    q.pop();

    if (here == 1)
    {
      break;
    }

    if (here % 3 == 0 &amp;&amp; !V[here / 3])
    {
      V[here / 3] = 1;
      P[here / 3] = here;
      q.emplace(here / 3);
    }

    if (here % 2 == 0 &amp;&amp; !V[here / 2])
    {
      V[here / 2] = 1;
      P[here / 2] = here;
      q.emplace(here / 2);
    }

    if (here - 1 &gt; 0 &amp;&amp; !V[here - 1])
    {
      V[here - 1] = 1;
      P[here - 1] = here;
      q.emplace(here - 1);
    }
  }
}

vector&lt;int&gt; path;

int main(void)
{
  scanf(&quot; %d&quot;, &amp;N);
  Bfs(N);

  int n = 1;
  while (P[n] != -1)
  {
    path.emplace_back(n);
    n = P[n];
  }

  printf(&quot;%d\n%d &quot;, (int)path.size(), N);
  for (auto r = path.rbegin(); r != path.rend(); ++r)
  {
    printf(&quot;%d &quot;, *r);
  }
  printf(&quot;\n&quot;);

  return 0;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[본대 산책 2]]></title>
            <link>https://velog.io/@aram_father/%EB%B3%B8%EB%8C%80-%EC%82%B0%EC%B1%85-2</link>
            <guid>https://velog.io/@aram_father/%EB%B3%B8%EB%8C%80-%EC%82%B0%EC%B1%85-2</guid>
            <pubDate>Sun, 03 Apr 2022 13:22:33 GMT</pubDate>
            <description><![CDATA[<p><strong>Problme link:</strong> <a href="https://www.acmicpc.net/problem/12850">https://www.acmicpc.net/problem/12850</a></p>
<p>Adjacent Matrix로 입력을 나타내고 이를 M이라고 하자.</p>
<p>이때, <code>M[i][j]</code>는 <code>i</code>번 건물에서 <code>j</code>번 건물에 도달하는 경우의 수를 나타낸다고 하자.</p>
<p>이렇게하면, <code>M^k[i][j]</code>은 자연스럽게, <code>k</code>분 만에 <code>i</code>번 건물에서 <code>j</code>번 건물에 도달하는 경우의 수를 나타낸다.</p>
<p>거듭제곱할 행렬의 크기가 꽤 크니까, 여기서는 분할 정복 방법을 이용해주자.</p>
<pre><code class="language-cpp">#include &lt;cstdio&gt;
#include &lt;cstdint&gt;

const int64_t kMod = 1000000007;

int64_t D;
int64_t M[8][8] = { { 0, 1, 1, 0, 0, 0, 0, 0 }, { 1, 0, 1, 1, 0, 0, 0, 0 }, { 1, 1, 0, 1, 1, 0, 0, 0 },
                    { 0, 1, 1, 0, 1, 1, 0, 0 }, { 0, 0, 1, 1, 0, 1, 1, 0 }, { 0, 0, 0, 1, 1, 0, 0, 1 },
                    { 0, 0, 0, 0, 1, 0, 0, 1 }, { 0, 0, 0, 0, 0, 1, 1, 0 } };

void Power(int64_t m[][8], const int64_t k)
{
  if (k == 1)
  {
    for (int64_t i = 0; i &lt; 8; ++i)
    {
      for (int64_t j = 0; j &lt; 8; ++j)
      {
        m[i][j] = M[i][j];
      }
    }

    return;
  }

  int64_t half[8][8];
  int64_t full[8][8];
  Power(half, k / 2);

  for (int64_t r = 0; r &lt; 8; ++r)
  {
    for (int64_t c = 0; c &lt; 8; ++c)
    {
      full[r][c] = 0;
      for (int64_t k = 0; k &lt; 8; ++k)
      {
        full[r][c] += half[r][k] * half[k][c];
        full[r][c] %= kMod;
      }
    }
  }

  if (k % 2)
  {
    for (int64_t r = 0; r &lt; 8; ++r)
    {
      for (int64_t c = 0; c &lt; 8; ++c)
      {
        m[r][c] = 0;
        for (int64_t k = 0; k &lt; 8; ++k)
        {
          m[r][c] += full[r][k] * M[k][c];
          m[r][c] %= kMod;
        }
      }
    }
  }
  else
  {
    for (int64_t r = 0; r &lt; 8; ++r)
    {
      for (int64_t c = 0; c &lt; 8; ++c)
      {
        m[r][c] = full[r][c];
      }
    }
  }

  return;
}

int main(void)
{
  scanf(&quot; %ld&quot;, &amp;D);

  int64_t ret[8][8];
  Power(ret, D);

  /*
  int64_t answer = 0;
  for (int64_t k = 0; k &lt; 8; ++k)
  {
    answer += ret[k][0];
    answer %= kMod;
  }
  */

  printf(&quot;%ld\n&quot;, ret[0][0]);

  return 0;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[가장 긴 증가하는 부분 수열 2]]></title>
            <link>https://velog.io/@aram_father/%EA%B0%80%EC%9E%A5-%EA%B8%B4-%EC%A6%9D%EA%B0%80%ED%95%98%EB%8A%94-%EB%B6%80%EB%B6%84-%EC%88%98%EC%97%B4-2</link>
            <guid>https://velog.io/@aram_father/%EA%B0%80%EC%9E%A5-%EA%B8%B4-%EC%A6%9D%EA%B0%80%ED%95%98%EB%8A%94-%EB%B6%80%EB%B6%84-%EC%88%98%EC%97%B4-2</guid>
            <pubDate>Sun, 03 Apr 2022 13:20:54 GMT</pubDate>
            <description><![CDATA[<p><strong>Problme link:</strong> <a href="https://www.acmicpc.net/problem/12015">https://www.acmicpc.net/problem/12015</a></p>
<p>사람마다 푸는 방법은 여러가지가 있을텐데, 나는 그중에 가장 무지성으로 풀 수 있는(물론 복잡도는 다른 알고리즘에 뒤지지 않는다) <code>lower_bound</code> 풀이를 사용했다.</p>
<p>이 풀이는 배열을 처음부터 끝 원소까지 순차적으로 훑어가면서 아래의 벡터(배열이 아니다, 동적으로 변하는 벡터다)를 유지한다.</p>
<ul>
<li><code>CACHE[len]: 길이가 len인 LIS중 끝 원소가 가장 작은 LIS의 끝 원소</code></li>
</ul>
<p>저 배열을 유지하는 방법은 아래와 같다.</p>
<p><code>i</code>번째 원소를 보고 있다고 하자.</p>
<p><code>CACHE</code>에서 <code>A[i]</code>의 <code>lower_bound</code>를 찾았고, 이 원소, <code>lb</code>,가 존재했다고 하자(즉, end를 리턴하지 않음).</p>
<p>그 이야기인 즉슨 <code>lb</code>를 <code>A[i]</code>로 바꿔치기 해도 여전히 <code>lb</code>로 끝났던 LIS만큼은 그대로 만들 수 있다는 이야기이다.</p>
<pre><code class="language-cpp">#include &lt;cstdio&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;

using namespace std;

int N;
vector&lt;int&gt; CACHE;

int main(void)
{
  scanf(&quot; %d&quot;, &amp;N);
  for (int it = 0; it &lt; N; ++it)
  {
    int number;
    scanf(&quot; %d&quot;, &amp;number);

    auto l = lower_bound(CACHE.begin(), CACHE.end(), number);
    if (l == CACHE.end())
    {
      CACHE.emplace_back(number);
    }
    else
    {
      *l = number;
    }
  }

  printf(&quot;%d\n&quot;, (int)CACHE.size());

  return 0;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[행렬 곱셈 순서]]></title>
            <link>https://velog.io/@aram_father/%ED%96%89%EB%A0%AC-%EA%B3%B1%EC%85%88-%EC%88%9C%EC%84%9C</link>
            <guid>https://velog.io/@aram_father/%ED%96%89%EB%A0%AC-%EA%B3%B1%EC%85%88-%EC%88%9C%EC%84%9C</guid>
            <pubDate>Wed, 23 Mar 2022 12:40:54 GMT</pubDate>
            <description><![CDATA[<p><strong>Problme link:</strong> <a href="https://www.acmicpc.net/problem/11049">https://www.acmicpc.net/problem/11049</a></p>
<p>그닥 어려울 것 없는 DP 문제로 쉽게 쉽게 풀어줄 수 있다.</p>
<p>아래와 같이 CACHE를 정의하자.</p>
<ul>
<li><code>CACHE[s][e]</code>: <code>Matrix[s]</code>부터 <code>Matrix[e]</code>까지 곱할 때 최소의 연산횟수</li>
</ul>
<p>그럼 점화식은 아래와 같이 유도할 수 있다.</p>
<ul>
<li><code>CACHE[s][e] = min(CACHE[s][m] + CACHE[m+1][e] + Matrix[s].row * Matrix[s].col * Matrix[e].col)</code></li>
</ul>
<p>결국 <code>Matrix[s..e]</code>를 <code>m</code>을 기준으로 두 파트로 나누어 보며 접근한다는 이야기이다.</p>
<p>굳이 주의할 점을 꼽아보자면 Bottom-up DP로 풀려면 루프 순서를 주의해주어야 한다는 점 정도가 있다.</p>
<pre><code class="language-cpp">#include &lt;cstdio&gt;
#include &lt;limits&gt;
#include &lt;utility&gt;
#include &lt;algorithm&gt;

using namespace std;

const int kMaxN = 500;

int N;
pair&lt;int, int&gt; M[kMaxN];

int CACHE[kMaxN][kMaxN];

int main(void)
{
  // Read input
  scanf(&quot; %d&quot;, &amp;N);
  for (int it = 0; it &lt; N; ++it)
  {
    scanf(&quot; %d %d&quot;, &amp;M[it].first, &amp;M[it].second);
  }

  // Solve
  for (int s = N - 1; s &gt;= 0; --s)
  {
    for (int e = s + 1; e &lt; N; ++e)
    {
      CACHE[s][e] = numeric_limits&lt;int&gt;::max();
      for (int m = s; m &lt; e; ++m)
      {
        CACHE[s][e] = min(CACHE[s][e], CACHE[s][m] + CACHE[m + 1][e] + M[s].first * M[m].second * M[e].second);
      }
    }
  }

  // Print answer
  printf(&quot;%d\n&quot;, CACHE[0][N - 1]);

  return 0;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[팰린드롬?]]></title>
            <link>https://velog.io/@aram_father/%ED%8C%B0%EB%A6%B0%EB%93%9C%EB%A1%AC</link>
            <guid>https://velog.io/@aram_father/%ED%8C%B0%EB%A6%B0%EB%93%9C%EB%A1%AC</guid>
            <pubDate>Wed, 23 Mar 2022 12:39:27 GMT</pubDate>
            <description><![CDATA[<p><strong>Problme link:</strong> <a href="https://www.acmicpc.net/problem/10942">https://www.acmicpc.net/problem/10942</a></p>
<p>문제 설명이 조금 부족한데, 숫자 하나를 문자 하나로 취급해야 한다.</p>
<p>여튼 노말하게 DP를 써주면 풀리는 문제이다.</p>
<p>아래와 같이 CACHE를 정의하자.</p>
<ul>
<li><code>CACHE[s][e]</code> = s ... e 번째 수가 palindrome인가?</li>
</ul>
<p>점화식은 아래와 같다.</p>
<ul>
<li><code>CACHE[s][e] = (CACHE[s+1][e-1] &amp;&amp; N[s] == N[e]) ? 1 : 0</code></li>
</ul>
<pre><code class="language-cpp">#include &lt;iostream&gt;

using namespace std;

int32_t N, M;
int32_t NUMBER[2000];
uint8_t CACHE[2000][2000];

int main(void)
{
  // For Faster IO
  ios_base::sync_with_stdio(false);
  cout.tie(nullptr);
  cin.tie(nullptr);

  // Read input
  cin &gt;&gt; N;
  for (int it = 0; it &lt; N; ++it)
  {
    cin &gt;&gt; NUMBER[it];
  }

  // DP
  for (int s = 0; s &lt; N; ++s)
  {
    CACHE[s][s] = 1;
  }

  for (int s = N - 2; s &gt;= 0; --s)
  {
    for (int e = s + 1; e &lt; N; ++e)
    {
      if (s + 1 &lt;= e - 1)
      {
        CACHE[s][e] = (CACHE[s + 1][e - 1] &amp;&amp; NUMBER[s] == NUMBER[e]) ? 1 : 0;
      }
      else
      {
        CACHE[s][e] = (NUMBER[s] == NUMBER[e]) ? 1 : 0;
      }
    }
  }

  // Solve
  cin &gt;&gt; M;
  for (int it = 0; it &lt; M; ++it)
  {
    int s, e;
    cin &gt;&gt; s &gt;&gt; e;
    cout &lt;&lt; (int)CACHE[s - 1][e - 1] &lt;&lt; &#39;\n&#39;;
  }

  return 0;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[공항]]></title>
            <link>https://velog.io/@aram_father/%EA%B3%B5%ED%95%AD</link>
            <guid>https://velog.io/@aram_father/%EA%B3%B5%ED%95%AD</guid>
            <pubDate>Fri, 18 Mar 2022 02:04:46 GMT</pubDate>
            <description><![CDATA[<p><strong>Problem link:</strong> <a href="https://www.acmicpc.net/problem/10775">https://www.acmicpc.net/problem/10775</a></p>
<p>이진 트리(i.e. std::set)을 활용해서 풀어주었다.</p>
<p>쉽게 풀고나서 혹시나 하는 마음에 문제 분류를 보니 Disjoint Set을 활용해서도 풀어줄 수 있는 모양이다.</p>
<p>시간복잡도 측면서에 내 풀이와 별반 다르지 않다는 생각이 들어서 다시 풀지는 않았다.</p>
<p>내 아이디어는 아래와 같다.</p>
<ul>
<li>1번 게이트, 2번 게이트 ..., G번 게이트를 내림차순으로 std::set에 저장한다.</li>
<li><code>1 ~ g_i</code>게이트에 도킹을 희망하는 비행기의 도킹 게이트는 위의 std::set에서 lower_bound로 찾아준다(역시 내림차순).</li>
<li>도킹을 못하면 더 이상 도킹 불가이니 그만 두고 답을 출력한다.</li>
<li>도킹을 할 수 있다면, lower_bound를 std::set에서 삭제해준다.</li>
</ul>
<pre><code class="language-cpp">#include &lt;set&gt;
#include &lt;cstdio&gt;

using namespace std;

int G;
int P;
int PLANES[100000];

int main(void)
{
  scanf(&quot; %d&quot;, &amp;G);
  set&lt;int&gt; gates;
  for (int g = 1; g &lt;= G; ++g)
  {
    gates.insert(-g);
  }

  scanf(&quot; %d&quot;, &amp;P);
  for (int it = 0; it &lt; P; ++it)
  {
    scanf(&quot; %d&quot;, &amp;PLANES[it]);
  }

  int answer;
  for (answer = 0; answer &lt; P; ++answer)
  {
    auto it = gates.lower_bound(-PLANES[answer]);
    if (it == gates.end())
    {
      break;
    }
    else
    {
      gates.erase(it);
    }
  }

  printf(&quot;%d\n&quot;, answer);

  return 0;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[열쇠]]></title>
            <link>https://velog.io/@aram_father/%EC%97%B4%EC%87%A0</link>
            <guid>https://velog.io/@aram_father/%EC%97%B4%EC%87%A0</guid>
            <pubDate>Wed, 16 Mar 2022 08:38:58 GMT</pubDate>
            <description><![CDATA[<p><strong>Problem link:</strong> <a href="https://www.acmicpc.net/problem/9328">https://www.acmicpc.net/problem/9328</a></p>
<p>빡 구현 문제이다.</p>
<p>아래의 순서로 풀어주면 된다.</p>
<ul>
<li>더 이상 새로운 열쇠도 발견하지 못하고, 문서도 발견하지 못할 때까지<ul>
<li>있는 열쇠로 열 수 있는 모든 문을 열어버린다(그 문까지 갈 수 있는지는 중요치 않음)</li>
<li>BFS를 돌면서 열쇠와 문서를 줍는다.</li>
</ul>
</li>
</ul>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;string&gt;
#include &lt;queue&gt;

using namespace std;

const int kMaxH = 100;
const int kMaxW = 100;

int H;
int W;
vector&lt;string&gt; BOARD;
vector&lt;bool&gt; KEYS;

void OpenDoors()
{
  for (int r = 0; r &lt; H; ++r)
  {
    for (int c = 0; c &lt; W; ++c)
    {
      if (&#39;A&#39; &lt;= BOARD[r][c] &amp;&amp; BOARD[r][c] &lt;= &#39;Z&#39; &amp;&amp; KEYS[BOARD[r][c] - &#39;A&#39;])
      {
        BOARD[r][c] = &#39;.&#39;;
      }
    }
  }
}

inline bool IsVisitable(const int r, const int c)
{
  return (BOARD[r][c] == &#39;.&#39; || BOARD[r][c] == &#39;$&#39; || (&#39;a&#39; &lt;= BOARD[r][c] &amp;&amp; BOARD[r][c] &lt;= &#39;z&#39;));
}

pair&lt;int, int&gt; BfsOnce()
{
  OpenDoors();

  vector&lt;vector&lt;bool&gt; &gt; visited(H, vector&lt;bool&gt;(W, false));
  queue&lt;pair&lt;int, int&gt; &gt; q;

  for (int r = 0; r &lt; H; ++r)
  {
    if (IsVisitable(r, 0))
    {
      visited[r][0] = true;
      q.emplace(r, 0);
    }
    if (IsVisitable(r, W - 1))
    {
      visited[r][W - 1] = true;
      q.emplace(r, W - 1);
    }
  }

  for (int c = 0; c &lt; W; ++c)
  {
    if (IsVisitable(0, c))
    {
      visited[0][c] = true;
      q.emplace(0, c);
    }
    if (IsVisitable(H - 1, c))
    {
      visited[H - 1][c] = true;
      q.emplace(H - 1, c);
    }
  }

  pair&lt;int, int&gt; ret(0, 0);

  while (!q.empty())
  {
    int r = q.front().first;
    int c = q.front().second;
    q.pop();

    if (BOARD[r][c] == &#39;$&#39;)
    {
      ++ret.first;
      BOARD[r][c] = &#39;.&#39;;
    }
    else if (&#39;a&#39; &lt;= BOARD[r][c] &amp;&amp; BOARD[r][c] &lt;= &#39;z&#39;)
    {
      if (!KEYS[BOARD[r][c] - &#39;a&#39;])
      {
        ++ret.second;
        KEYS[BOARD[r][c] - &#39;a&#39;] = true;
        BOARD[r][c] = &#39;.&#39;;
      }
    }

    const int dr[4] = { -1, 0, 1, 0 };
    const int dc[4] = { 0, 1, 0, -1 };

    for (int dir = 0; dir &lt; 4; ++dir)
    {
      int nr = r + dr[dir];
      int nc = c + dc[dir];
      if (0 &gt; nr || nr &gt;= H || 0 &gt; nc || nc &gt;= W)
      {
        continue;
      }
      if (!visited[nr][nc] &amp;&amp; IsVisitable(nr, nc))
      {
        visited[nr][nc] = true;
        q.emplace(nr, nc);
      }
    }
  }

  return ret;
}

int Solve()
{
  int answer = 0;
  while (true)
  {
    auto ret = BfsOnce();
    if (ret.first == 0 &amp;&amp; ret.second == 0)
    {
      break;
    }

    answer += ret.first;
  }

  return answer;
}

int main(void)
{
  // For faster IO
  ios_base::sync_with_stdio(false);
  cout.tie(nullptr);
  cin.tie(nullptr);

  int testcase;
  cin &gt;&gt; testcase;

  while (testcase--)
  {
    // Read input
    cin &gt;&gt; H &gt;&gt; W;
    BOARD.assign(H, &quot;&quot;);
    KEYS.assign(26, false);
    for (int r = 0; r &lt; H; ++r)
    {
      cin &gt;&gt; BOARD[r];
    }

    string keys;
    cin &gt;&gt; keys;
    if (keys.compare(&quot;0&quot;) != 0)
    {
      for (auto ch : keys)
      {
        KEYS[ch - &#39;a&#39;] = true;
      }
    }

    // Solve
    cout &lt;&lt; Solve() &lt;&lt; &#39;\n&#39;;
  }

  return 0;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[LCS 2]]></title>
            <link>https://velog.io/@aram_father/LCS-2</link>
            <guid>https://velog.io/@aram_father/LCS-2</guid>
            <pubDate>Tue, 15 Mar 2022 02:54:01 GMT</pubDate>
            <description><![CDATA[<p><strong>Problme link:</strong> <a href="https://www.acmicpc.net/problem/9252">https://www.acmicpc.net/problem/9252</a></p>
<p>전형적인 DP문제이고, DP 완료 후 백트래킹 정도가 추가된 문제이다.</p>
<p>아래와 같이 CACHE를 정의하자.</p>
<ul>
<li><code>CACHE[i][j]</code>: <code>A[0...i]</code>, <code>B[0...j]</code>까지 고려할 때 LCS의 길이</li>
</ul>
<p>그럼 점화식은 아래와 같다.</p>
<ul>
<li><code>CACHE[i][j] = max(CACHE[i-1][j-1] + 1, CACHE[i-1][j], CACHE[i][j-1])</code> (단, <code>CACHE[i-1][j-1] + 1</code> 항은 <code>A[i] == B[j]</code>일 때만 고려)</li>
</ul>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;algorithm&gt;

using namespace std;

const int kMaxN = 1000;

string A;
string B;
int CACHE[kMaxN][kMaxN];

int GetLcsLength(const int i, const int j)
{
  if (i &lt; 0 || j &lt; 0)
  {
    return 0;
  }

  int&amp; ret = CACHE[i][j];

  if (ret != -1)
  {
    return ret;
  }

  if (A[i] == B[j])
  {
    ret = GetLcsLength(i - 1, j - 1) + 1;
  }
  else
  {
    ret = max(GetLcsLength(i - 1, j), GetLcsLength(i, j - 1));
  }

  return ret;
}

string GetLcs(const int i, const int j)
{
  if (i &lt; 0 || j &lt; 0)
  {
    return &quot;&quot;;
  }
  else if (A[i] == B[j])
  {
    return GetLcs(i - 1, j - 1) + A[i];
  }
  else if (GetLcsLength(i - 1, j) &gt;= GetLcsLength(i, j - 1))
  {
    return GetLcs(i - 1, j);
  }
  else
  {
    return GetLcs(i, j - 1);
  }
}

int main(void)
{
  // Initialize
  for (int i = 0; i &lt; kMaxN; ++i)
  {
    for (int j = 0; j &lt; kMaxN; ++j)
    {
      CACHE[i][j] = -1;
    }
  }

  // For faster IO
  ios_base::sync_with_stdio(false);
  cout.tie(nullptr);
  cin.tie(nullptr);

  // Read inputs
  cin &gt;&gt; A &gt;&gt; B;

  // Solve
  cout &lt;&lt; GetLcsLength(A.size() - 1, B.size() - 1) &lt;&lt; &#39;\n&#39;;
  if (GetLcsLength(A.size() - 1, B.size() - 1))
  {
    cout &lt;&lt; GetLcs(A.size() - 1, B.size() - 1) &lt;&lt; &#39;\n&#39;;
  }

  return 0;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[행성 터널]]></title>
            <link>https://velog.io/@aram_father/%ED%96%89%EC%84%B1-%ED%84%B0%EB%84%90</link>
            <guid>https://velog.io/@aram_father/%ED%96%89%EC%84%B1-%ED%84%B0%EB%84%90</guid>
            <pubDate>Sun, 13 Mar 2022 06:42:54 GMT</pubDate>
            <description><![CDATA[<p><strong>Problme link:</strong> <a href="https://www.acmicpc.net/problem/2887">https://www.acmicpc.net/problem/2887</a></p>
<p>문제를 보는 순간 바로 MST문제로 분류할 수 있었다.</p>
<p>하지만, 입력이 사실상 fully connected graph이므로 Prim이건, Kruskal이건 바로는 사용하지 못하는 문제였다.</p>
<p>첨에는 이진 트리를 사용하는 Prim으로 접근했었는데, 좋은 결과를 얻지 못했고,</p>
<p>  결국에는 웹 서칭을 해서 아이디어를 얻었다...ㅎㅎ</p>
<p>  아리디어의 핵심은 모든 간선을 다 볼 필요 없이 축 별로 인접한 녀석들만 봐주자는 것이다.</p>
<p>  아마 구글 검색어 노출도 안되는 내 블로그까지 흘러들어와서 내 글을 보고 있는 당신은 <strong><code>대체 그게 왜 되는데?</code></strong>에 대한 의문을 품고 있으리라.</p>
<p>  나 역시 증명에 시간을 꽤 할애하였으므로 증명을 보다 자세히 적어보도록 하겠다.</p>
<p>  <strong>claim:</strong> 모든 간선이 (x축 || y축 || z축)에서 인접한 두 정점으로 이루어진 MST가 존재한다.</p>
<p>  <strong>proof:</strong></p>
<ul>
<li>귀류법으로 증명한다.</li>
<li>MST <code>M</code>내에 존재하는 어떠한 간선 <code>(p, q)</code>가 x, y, z 축 어디에서도 인접하지 않았다고 가정하자.</li>
<li>일반성을 잃지 않고 <code>w(p, q) == |p.x - q.x|</code>였다고 가정하자.</li>
<li>가정에 의해 <code>w(p, r) &lt;= w(p, q)</code>를 만족하는 <code>r</code>이 존재한다.</li>
<li><code>M</code>에서 <code>(p, q)</code>를 삭제하면 <code>M</code>은 2개의 트리로 분리된다.</li>
<li>역시 일반성을 잃지 않고, <code>r</code>이 <code>q</code>가 속한 트리에 속해있다고 하자.</li>
<li>간선 <code>(r, p)</code>를 추가하면 2개의 트리로 분리되었던 <code>M</code>은 다시 하나의 트리가 된다. 이를 <code>M_new</code>이라 하자.</li>
<li><code>w(p, r) &lt;= w(p, q)</code>이므로 <code>M_new</code>의 가중치 합이 <code>M</code>보다 작거나 같다.</li>
<li>작다면 가정에 모순이고, 같다면 위와 같이 바꾸어 나가면 된다.</li>
</ul>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;algorithm&gt;
#include &lt;cstdint&gt;
#include &lt;vector&gt;

using namespace std;

inline int abs(const int x)
{
  return x &gt;= 0 ? x : -x;
}

struct Planet
{
  int id;
  int x, y, z;

  Planet(const int id, const int x, const int y, const int z) : id(id), x(x), y(y), z(z)
  {
  }
};

struct XComparator
{
  bool operator()(const Planet&amp; a, const Planet&amp; b)
  {
    return a.x &lt; b.x;
  }
};

struct YComparator
{
  bool operator()(const Planet&amp; a, const Planet&amp; b)
  {
    return a.y &lt; b.y;
  }
};

struct ZComparator
{
  bool operator()(const Planet&amp; a, const Planet&amp; b)
  {
    return a.z &lt; b.z;
  }
};

struct Edge
{
  int src;
  int dst;
  int weight;
  Edge(const int src, const int dst, const int weight) : src(src), dst(dst), weight(weight)
  {
  }

  bool operator&lt;(const Edge&amp; rhs) const
  {
    return weight &lt; rhs.weight;
  }
};

class DisjointSet
{
private:
  vector&lt;int&gt; parents_;

public:
  DisjointSet(const int size) : parents_(size, -1)
  {
  }

  int Find(const int elem)
  {
    if (parents_[elem] == -1)
    {
      return elem;
    }
    else
    {
      return (parents_[elem] = Find(parents_[elem]));
    }
  }

  void Union(const int a, const int b)
  {
    parents_[Find(a)] = Find(b);
  }
};

int N;
vector&lt;Planet&gt; PLANETS;
vector&lt;Edge&gt; EDGES;

int64_t Kruskal()
{
  int64_t answer = 0;

  DisjointSet dset((int)EDGES.size());
  sort(EDGES.begin(), EDGES.end());

  int num_of_planets = 1;

  for (const auto&amp; edge : EDGES)
  {
    if (num_of_planets == N)
    {
      break;
    }

    if (dset.Find(edge.src) != dset.Find(edge.dst))
    {
      answer += edge.weight;
      dset.Union(edge.src, edge.dst);
      ++num_of_planets;
    }
  }

  return answer;
}

int main(void)
{
  // For faster IO
  ios_base::sync_with_stdio(false);
  cout.tie(nullptr);
  cin.tie(nullptr);

  // Read input
  cin &gt;&gt; N;
  for (int id = 0; id &lt; N; ++id)
  {
    int x, y, z;
    cin &gt;&gt; x &gt;&gt; y &gt;&gt; z;
    PLANETS.emplace_back(id, x, y, z);
  }

  // Extract meaningful edges
  sort(PLANETS.begin(), PLANETS.end(), XComparator());
  for (size_t it = 0; it + 1 &lt; PLANETS.size(); ++it)
  {
    EDGES.emplace_back(PLANETS[it].id, PLANETS[it + 1].id, abs(PLANETS[it].x - PLANETS[it + 1].x));
  }

  sort(PLANETS.begin(), PLANETS.end(), YComparator());
  for (size_t it = 0; it + 1 &lt; PLANETS.size(); ++it)
  {
    EDGES.emplace_back(PLANETS[it].id, PLANETS[it + 1].id, abs(PLANETS[it].y - PLANETS[it + 1].y));
  }

  sort(PLANETS.begin(), PLANETS.end(), ZComparator());
  for (size_t it = 0; it + 1 &lt; PLANETS.size(); ++it)
  {
    EDGES.emplace_back(PLANETS[it].id, PLANETS[it + 1].id, abs(PLANETS[it].z - PLANETS[it + 1].z));
  }

  // Kruskal
  cout &lt;&lt; Kruskal() &lt;&lt; &#39;\n&#39;;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[음악프로그램]]></title>
            <link>https://velog.io/@aram_father/%EC%9D%8C%EC%95%85%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8</link>
            <guid>https://velog.io/@aram_father/%EC%9D%8C%EC%95%85%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8</guid>
            <pubDate>Sun, 13 Mar 2022 06:41:14 GMT</pubDate>
            <description><![CDATA[<p><strong>Problme link:</strong> <a href="https://www.acmicpc.net/problem/2623">https://www.acmicpc.net/problem/2623</a></p>
<p>간단한 위상정렬 문제로 볼 수 있다.</p>
<p>각 가수를 그래프의 정점으로, 인접한 두 순서를 간선으로 표현한다면 입력은 그래프로 표현될 수 있다.</p>
<p>그래프의 순서를 유지하는 위상정렬 결과를 아무거나 하나 출력해주면 된다.</p>
<p>주의할 점으로는 아래의 것들이 있을 수 있다.</p>
<ul>
<li>입력이 꼭 하나의 그래프로 표현되지 않을 수도 있다(2개 이상의 세그먼트)<ul>
<li>사이클을 이루는지의 판단이 필요하다(불가능한 경우 판별을 위해)</li>
</ul>
</li>
<li>방향성 그래프에서 사이클 유무는 아래와 같이 간단하게 알 수 있다.</li>
<li>DFS를 수행하면서,</li>
<li>인접한 정점이 이미 방문상태인데,</li>
<li>그 정점의 DFS가 완료되지 않았다.</li>
</ul>
<pre><code class="language-cpp">#include &lt;cstdio&gt;
#include &lt;vector&gt;

using namespace std;

int N;
int M;
vector&lt;bool&gt; V;
vector&lt;bool&gt; F;
vector&lt;vector&lt;int&gt; &gt; G;

bool DoDfs(int here, vector&lt;int&gt;&amp; topology)
{
  V[here] = true;
  for (const auto&amp; there : G[here])
  {
    if (!V[there])
    {
      if (!DoDfs(there, topology))
      {
        return false;
      }
    }
    else if (!F[there])
    {
      return false;
    }
  }

  topology.emplace_back(here);
  F[here] = true;
  return true;
}

void Solve()
{
  vector&lt;int&gt; answer;
  for (int singer = 1; singer &lt;= N; ++singer)
  {
    if (!V[singer] &amp;&amp; !DoDfs(singer, answer))
    {
      printf(&quot;%d\n&quot;, 0);
    }
  }

  for (auto it = answer.rbegin(); it != answer.rend(); ++it)
  {
    printf(&quot;%d\n&quot;, *it);
  }

  return;
}

int main(void)
{
  // Read input
  scanf(&quot; %d %d&quot;, &amp;N, &amp;M);
  V.assign(N + 1, false);
  F.assign(N + 1, false);
  G.assign(N + 1, vector&lt;int&gt;());
  for (int pd = 0; pd &lt; M; ++pd)
  {
    int num_of_singers;
    int predecessor;
    int successor;
    scanf(&quot; %d %d&quot;, &amp;num_of_singers, &amp;predecessor);

    for (int singer = 1; singer &lt; num_of_singers; ++singer)
    {
      scanf(&quot; %d&quot;, &amp;successor);
      G[predecessor].emplace_back(successor);
      predecessor = successor;
    }
  }

  // Solve
  Solve();

  return 0;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[세 용액]]></title>
            <link>https://velog.io/@aram_father/%EC%84%B8-%EC%9A%A9%EC%95%A1</link>
            <guid>https://velog.io/@aram_father/%EC%84%B8-%EC%9A%A9%EC%95%A1</guid>
            <pubDate>Sun, 06 Mar 2022 15:38:51 GMT</pubDate>
            <description><![CDATA[<p><strong>Problem link:</strong> <a href="https://www.acmicpc.net/problem/2473">https://www.acmicpc.net/problem/2473</a></p>
<p>정렬된 배열에서 서로 다른 3개의 원소 a, b, c를 뽑아 a + b + c = 0이 되도록하는 경우를 헤아리는 문제와 비슷하다.</p>
<p><code>a &lt;= b &lt;= c</code>가 되도록 순서를 강제해주고, 각 <code>a</code>에 대해서 투 포인터를 진행해준다.</p>
<pre><code class="language-cpp">#include &lt;cstdio&gt;
#include &lt;cstdint&gt;
#include &lt;algorithm&gt;
#include &lt;limits&gt;

using namespace std;

inline int64_t ABS(const int64_t x)
{
  return x &gt;= 0 ? x : -x;
}

const int kMaxN = 5000;
const int64_t kMaxAcidity = numeric_limits&lt;int64_t&gt;::max();

int N;
int64_t ACIDITY[kMaxN];

void Solve()
{
  sort(ACIDITY, ACIDITY + N);

  int64_t min_acidity = kMaxAcidity;
  int64_t l1, l2, l3;

  for (int a = 0; a &lt; N; ++a)
  {
    int lo = a + 1;
    int hi = N - 1;

    while (lo &lt; hi)
    {
      int64_t sum = ACIDITY[a] + ACIDITY[lo] + ACIDITY[hi];
      if (ABS(sum) &lt; min_acidity)
      {
        min_acidity = ABS(sum);
        l1 = ACIDITY[a];
        l2 = ACIDITY[lo];
        l3 = ACIDITY[hi];
      }

      if (sum &lt; 0)
      {
        ++lo;
      }
      else
      {
        --hi;
      }
    }
  }

  printf(&quot;%ld %ld %ld\n&quot;, l1, l2, l3);
}

int main(void)
{
  scanf(&quot; %d&quot;, &amp;N);
  for (int it = 0; it &lt; N; ++it)
  {
    scanf(&quot; %ld&quot;, &amp;ACIDITY[it]);
  }

  Solve();

  return 0;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Dance Dance Revolution]]></title>
            <link>https://velog.io/@aram_father/Dance-Dance-Revolution</link>
            <guid>https://velog.io/@aram_father/Dance-Dance-Revolution</guid>
            <pubDate>Sat, 05 Mar 2022 16:44:55 GMT</pubDate>
            <description><![CDATA[<p><strong>Problme link:</strong> <a href="https://www.acmicpc.net/problem/2342">https://www.acmicpc.net/problem/2342</a></p>
<p>그닥 어렵지 않게 풀 수 있는 DP 문제이다.</p>
<p>아래와 같이 CACHE를 정의하였다.</p>
<ul>
<li><code>CACHE[i][l][r] = i번째 입력까지 밟고, 오른발이 r, 왼발이 l에 있을 때의 최소 비용</code></li>
</ul>
<p>사실 i번째 입력을 밟았다는 사실이 l, r 중 하나가 i번째 입력에 있음을 의미한다.</p>
<p>따라서, 남은 한발만 저장하는 방식으로 조금 더 최적화를 할 수는 있지만 굳이 그럴 것 까지는 없어보여 진행하지 않았다.</p>
<p>점화식은 간단하게, 왼발로 온 경우, 오른 발로 온 경우를 나누어 구해주면 된다.</p>
<pre><code class="language-cpp">#include &lt;cstdio&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;

using namespace std;

const int kMaxN = 100000;
const int kMaxCost = kMaxN * 5;

const int kCost[5][5] = { { 0, 2, 2, 2, 2 },
                          { kMaxCost, 1, 3, 4, 3 },
                          { kMaxCost, 3, 1, 3, 4 },
                          { kMaxCost, 4, 3, 1, 3 },
                          { kMaxCost, 3, 4, 3, 1 } };

vector&lt;int&gt; SEQUENCE;

int CACHE[kMaxN][5][5];

int Solve()
{
  CACHE[0][SEQUENCE[0]][0] = 2;
  CACHE[0][0][SEQUENCE[0]] = 2;

  for (size_t seq = 1; seq &lt; SEQUENCE.size(); ++seq)
  {
    for (int lr = 0; lr &lt; 25; ++lr)
    {
      const int l = lr / 5;
      const int r = lr % 5;

      if (SEQUENCE[seq] != l &amp;&amp; SEQUENCE[seq] != r)
      {
        continue;
      }

      if (l == r)
      {
        continue;
      }

      for (int p = 0; p &lt; 5; ++p)
      {
        if (SEQUENCE[seq] == l)
        {
          CACHE[seq][l][r] = min(CACHE[seq][l][r], CACHE[seq - 1][p][r] + kCost[p][l]);
        }
        else
        {
          CACHE[seq][l][r] = min(CACHE[seq][l][r], CACHE[seq - 1][l][p] + kCost[p][r]);
        }
      }
    }
  }

  int answer = kMaxCost;
  for (int left = 0; left &lt; 5; ++left)
  {
    for (int right = 0; right &lt; 5; ++right)
    {
      answer = min(answer, CACHE[SEQUENCE.size() - 1][left][right]);
    }
  }

  return answer;
}

int main(void)
{
  while (true)
  {
    int target;
    scanf(&quot; %d&quot;, &amp;target);

    if (target == 0)
    {
      break;
    }

    SEQUENCE.emplace_back(target);
  }

  for (int i = 0; i &lt; kMaxN; ++i)
  {
    for (int j = 0; j &lt; 5; ++j)
    {
      for (int k = 0; k &lt; 5; ++k)
      {
        CACHE[i][j][k] = kMaxCost;
      }
    }
  }

  printf(&quot;%d\n&quot;, Solve());

  return 0;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[스도쿠]]></title>
            <link>https://velog.io/@aram_father/%EC%8A%A4%EB%8F%84%EC%BF%A0</link>
            <guid>https://velog.io/@aram_father/%EC%8A%A4%EB%8F%84%EC%BF%A0</guid>
            <pubDate>Sat, 05 Mar 2022 16:43:01 GMT</pubDate>
            <description><![CDATA[<p><strong>Problme link:</strong> <a href="https://www.acmicpc.net/problem/2239">https://www.acmicpc.net/problem/2239</a></p>
<p>별 볼일 없는 백 트래킹 문제였다.</p>
<p>포인트 냠냠</p>
<pre><code class="language-cpp">#include &lt;cstdio&gt;

using namespace std;

const int kSize = 9;

int board[kSize][kSize];

void PrintBoard()
{
  for (int r = 0; r &lt; kSize; ++r)
  {
    for (int c = 0; c &lt; kSize; ++c)
    {
      printf(&quot;%d&quot;, board[r][c]);
    }
    printf(&quot;\n&quot;);
  }
}

bool Solve(const int idx)
{
  if (idx &gt;= kSize * kSize)
  {
    PrintBoard();
    return true;
  }

  int row = idx / kSize;
  int col = idx % kSize;

  if (board[row][col] != 0)
  {
    return Solve(idx + 1);
  }

  bool used[kSize + 1] = {
    false,
  };

  for (int c = 0; c &lt; kSize; ++c)
  {
    used[board[row][c]] = true;
  }

  for (int r = 0; r &lt; kSize; ++r)
  {
    used[board[r][col]] = true;
  }

  int offset_row = 3 * (row / 3);
  int offset_col = 3 * (col / 3);
  for (int r = 0; r &lt; 3; ++r)
  {
    for (int c = 0; c &lt; 3; ++c)
    {
      used[board[offset_row + r][offset_col + c]] = true;
    }
  }

  for (int number = 1; number &lt;= kSize; ++number)
  {
    if (!used[number])
    {
      board[row][col] = number;
      if (Solve(idx + 1))
      {
        return true;
      }
    }
  }

  board[row][col] = 0;
  return false;
}

int main(void)
{
  for (int r = 0; r &lt; 9; ++r)
  {
    for (int c = 0; c &lt; 9; ++c)
    {
      scanf(&quot; %1d&quot;, &amp;board[r][c]);
    }
  }

  Solve(0);

  return 0;
}

</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[용액]]></title>
            <link>https://velog.io/@aram_father/%EC%9A%A9%EC%95%A1</link>
            <guid>https://velog.io/@aram_father/%EC%9A%A9%EC%95%A1</guid>
            <pubDate>Sat, 05 Mar 2022 16:38:47 GMT</pubDate>
            <description><![CDATA[<p><strong>Problem link:</strong> <a href="https://www.acmicpc.net/problem/2467">https://www.acmicpc.net/problem/2467</a></p>
<p>노말한 투 포인터 문제로, 서로 반대 방향에서 출발하는 투 포인터 알고리즘을 사용해주자.</p>
<pre><code class="language-cpp">#include &lt;cstdio&gt;
#include &lt;limits&gt;
#include &lt;algorithm&gt;

using namespace std;

inline int abs(const int x)
{
    return x &gt;= 0 ? x : -x;
}

const int kMaxN = 100000;

int N;
int LIQUID[kMaxN];

void Solve()
{
    int answer_thickness = numeric_limits&lt;int&gt;::max();
    int answer_lo;
    int answer_hi;

    int lo = 0;
    int hi = N - 1;
    while (lo &lt; hi)
    {
        int sum = LIQUID[lo] + LIQUID[hi];
        if (abs(sum) &lt; answer_thickness)
        {
            answer_thickness = abs(sum);
            answer_lo = lo;
            answer_hi = hi;
        }

        if (sum == 0)
        {
            break;
        }
        else if (sum &lt; 0)
        {
            ++lo;
        }
        else
        {
            --hi;
        }
    }

    printf(&quot;%d %d\n&quot;, LIQUID[answer_lo], LIQUID[answer_hi]);
}


int main(void)
{
    // Read Input
    scanf(&quot; %d&quot;, &amp;N);
    for (int it = 0; it &lt; N; ++it)
    {
        scanf(&quot; %d&quot;, &amp;LIQUID[it]);
    }

    // Solve
    Solve();

    return 0;
}

</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[선분 그룹]]></title>
            <link>https://velog.io/@aram_father/%EC%84%A0%EB%B6%84-%EA%B7%B8%EB%A3%B9</link>
            <guid>https://velog.io/@aram_father/%EC%84%A0%EB%B6%84-%EA%B7%B8%EB%A3%B9</guid>
            <pubDate>Fri, 04 Mar 2022 03:14:05 GMT</pubDate>
            <description><![CDATA[<p><strong>Problme link:</strong> <a href="https://www.acmicpc.net/problem/2162">https://www.acmicpc.net/problem/2162</a></p>
<p>문제가 어렵다기 보다는 자료구조를 여러개 써줘야한다.</p>
<ul>
<li>CCW를 활용한 선분 교차여부 판단을 위해서 벡터, 라인 자료구조를 사용하였고,</li>
<li>그루핑을 위해 서로소 집합을 사용하였다.</li>
</ul>
<p>CCW를 활용하는 교차여부 판단 시 둘 다 0인 경우에만 예외처리가 필요함을 잘 기억해두도록하자.</p>
<pre><code class="language-cpp">#include &lt;cstdio&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;
#include &lt;cstdint&gt;

using namespace std;

int N;

class Vector
{
public:
  int64_t x, y;

  Vector()
  {
  }
  Vector(const int64_t x, const int64_t y) : x(x), y(y)
  {
  }

  int64_t operator*(const Vector&amp; rhs) const
  {
    return x * rhs.y - y * rhs.x;
  }

  Vector operator-(const Vector&amp; rhs) const
  {
    return Vector(x - rhs.x, y - rhs.y);
  }

  bool operator&lt;(const Vector&amp; rhs) const
  {
    if (x != rhs.x)
    {
      return x &lt; rhs.x;
    }

    return y &lt; rhs.y;
  }
};

class Line
{
public:
  Vector start, end;

  Line()
  {
  }
  Line(const Vector&amp; start, const Vector&amp; end) : start(start), end(end)
  {
    if (end &lt; start)
    {
      swap&lt;Vector&gt;(this-&gt;start, this-&gt;end);
    }
  }
};

bool HasIntersect(const Line&amp; l1, const Line&amp; l2)
{
  int64_t l1_l2 = ((l1.end - l1.start) * (l2.start - l1.end)) * ((l1.end - l1.start) * (l2.end - l1.end));
  int64_t l2_l1 = ((l2.end - l2.start) * (l1.start - l2.end)) * ((l2.end - l2.start) * (l1.end - l2.end));

  if (l1_l2 == 0 &amp;&amp; l2_l1 == 0)
  {
    return !(l1.end &lt; l2.start || l2.end &lt; l1.start);
  }

  return l1_l2 &lt;= 0 &amp;&amp; l2_l1 &lt;= 0;
}

class Set
{
public:
  vector&lt;int&gt; parent;
  vector&lt;int&gt; number_of_elem;
  Set(const int size) : parent(size, -1), number_of_elem(size, 1)
  {
  }
  int Find(const int idx)
  {
    if (parent[idx] != -1)
    {
      parent[idx] = Find(parent[idx]);
      return parent[idx];
    }
    return idx;
  }
  void Union(const int a, const int b)
  {
    int root_a = Find(a);
    int root_b = Find(b);
    if (root_a == root_b)
    {
      return;
    }
    parent[root_a] = root_b;
    number_of_elem[root_b] += number_of_elem[root_a];
  }
};

void Solve(const vector&lt;Line&gt;&amp; lines)
{
  Set dset(N);

  for (int i = 0; i &lt; N; ++i)
  {
    for (int j = i + 1; j &lt; N; ++j)
    {
      if (HasIntersect(lines[i], lines[j]))
      {
        dset.Union(i, j);
      }
    }
  }

  int number_of_group = 0;
  int max_group_size = -1;

  for (int i = 0; i &lt; N; ++i)
  {
    if (dset.parent[i] == -1)
    {
      ++number_of_group;
      max_group_size = max(max_group_size, dset.number_of_elem[i]);
    }
  }

  printf(&quot;%d\n%d\n&quot;, number_of_group, max_group_size);
}

int main(void)
{
  // Read input
  scanf(&quot; %d&quot;, &amp;N);
  vector&lt;Line&gt; lines;
  for (int it = 0; it &lt; N; ++it)
  {
    Vector start, end;
    scanf(&quot; %ld %ld %ld %ld&quot;, &amp;start.x, &amp;start.y, &amp;end.x, &amp;end.y);
    lines.emplace_back(start, end);
  }

  // Solve
  Solve(lines);

  return 0;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[두 배열의 합]]></title>
            <link>https://velog.io/@aram_father/%EB%91%90-%EB%B0%B0%EC%97%B4%EC%9D%98-%ED%95%A9</link>
            <guid>https://velog.io/@aram_father/%EB%91%90-%EB%B0%B0%EC%97%B4%EC%9D%98-%ED%95%A9</guid>
            <pubDate>Fri, 04 Mar 2022 03:12:13 GMT</pubDate>
            <description><![CDATA[<p><strong>Problme link:</strong> <a href="https://www.acmicpc.net/problem/2143">https://www.acmicpc.net/problem/2143</a></p>
<p>각 배열의 모든 부분합들을 미리 구하여 저장해놓는다.</p>
<p>이렇게 구해진 두 개의 부분합 배열을 각각 <code>CAND_A</code>, <code>CAND_B</code>라고 하자.</p>
<p>두 부분합 배열을 정렬한 뒤에 서로 다른 방향에서 시작하는 투 포인터 아이디어를 적용해주면 답을 쉽게 구할 수 있다.</p>
<p>단, 주의할 점으로는 투 포인터 아이디어는 정렬한 배열이 같은 원소를 포함하게 되는 경우 제대로 카운팅을 하기 어려워지는 문제가 있다는 점이다.</p>
<p>예를 들어, <code>CAND_A</code>, <code>CAND_B</code>가 아래와 같이 주어지고 <code>lo</code>, <code>hi</code>가 아래와 같다고 해보자.</p>
<ul>
<li><code>CAND_A: ... 3(lo) 3 3 ...</code></li>
<li><code>CAND_B: ... 3 3 3(hi) ...</code></li>
</ul>
<p>이 경우 <code>T=6</code>이라면, lo 또는 hi를 이동시키는 아이디어로는 올바르게 경우의 수를 셀 수 없다.</p>
<p>따라서, 나는 중복을 허용하지 않도록 <code>CAND_A</code>, <code>CAND_B</code>를 값, 빈도의 map으로 관리하였다.</p>
<pre><code class="language-cpp">#include &lt;cstdio&gt;
#include &lt;cstdint&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;
#include &lt;map&gt;

using namespace std;

int T;
int N;
int M;
vector&lt;int&gt; PSUM_A;
vector&lt;int&gt; PSUM_B;
map&lt;int, int&gt; CAND_A;
map&lt;int, int&gt; CAND_B;

int main(void)
{
  scanf(&quot; %d&quot;, &amp;T);

  scanf(&quot; %d&quot;, &amp;N);
  PSUM_A.emplace_back(0);
  for (int it = 1; it &lt;= N; ++it)
  {
    int a;
    scanf(&quot; %d&quot;, &amp;a);
    PSUM_A.emplace_back(a + PSUM_A[it - 1]);
  }

  scanf(&quot; %d&quot;, &amp;M);
  PSUM_B.emplace_back(0);
  for (int it = 1; it &lt;= M; ++it)
  {
    int b;
    scanf(&quot; %d&quot;, &amp;b);
    PSUM_B.emplace_back(b + PSUM_B[it - 1]);
  }

  for (int i = 1; i &lt;= N; ++i)
  {
    for (int j = i; j &lt;= N; ++j)
    {
      ++CAND_A[PSUM_A[j] - PSUM_A[i - 1]];
    }
  }

  for (int i = 1; i &lt;= M; ++i)
  {
    for (int j = i; j &lt;= M; ++j)
    {
      ++CAND_B[PSUM_B[j] - PSUM_B[i - 1]];
    }
  }

  int64_t answer = 0;
  auto lo = CAND_A.begin();
  auto hi = CAND_B.rbegin();

  while (lo != CAND_A.end() &amp;&amp; hi != CAND_B.rend())
  {
    int sum = lo-&gt;first + hi-&gt;first;
    if (sum == T)
    {
      answer += (int64_t)lo-&gt;second * (int64_t)hi-&gt;second;
      ++lo;
      ++hi;
    }
    else if (sum &lt; T)
    {
      ++lo;
    }
    else
    {
      ++hi;
    }
  }

  printf(&quot;%ld\n&quot;, answer);

  return 0;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[외판원 순회]]></title>
            <link>https://velog.io/@aram_father/%EC%99%B8%ED%8C%90%EC%9B%90-%EC%88%9C%ED%9A%8C</link>
            <guid>https://velog.io/@aram_father/%EC%99%B8%ED%8C%90%EC%9B%90-%EC%88%9C%ED%9A%8C</guid>
            <pubDate>Fri, 04 Mar 2022 03:10:25 GMT</pubDate>
            <description><![CDATA[<p><strong>Problme link:</strong> <a href="https://www.acmicpc.net/problem/2098">https://www.acmicpc.net/problem/2098</a></p>
<p>고전적인 문제이니만큼 DP를 잘 활용해서 풀어주면 무난하게 풀린다.</p>
<p>단, 한 가지가 가물가물해서 조금 시간을 버렸는데 아래 사실을 유념하도록 하자.</p>
<ul>
<li>어느 도시에서 시작하는 순회를 구하건 답은 같다(사이클이므로)</li>
<li>따라서, 항상 0번 도시에서 시작하고 돌아오는 경우를 구해주자</li>
</ul>
<pre><code class="language-cpp">#include &lt;cstdio&gt;
#include &lt;vector&gt;
#include &lt;utility&gt;
#include &lt;algorithm&gt;

using namespace std;

typedef pair&lt;int, int&gt; neighbor_t;

const int kMaxN = 16;
const int kMaxCost = 1000000;

int N;
vector&lt;vector&lt;neighbor_t&gt; &gt; ADJ;
int CACHE[kMaxN][1 &lt;&lt; kMaxN];

int Solve(const int city, const int visit)
{
  if (visit + 1 == (1 &lt;&lt; N))
  {
    if (city == 0)
    {
      return 0;
    }
    else
    {
      for (const auto&amp; neighbor : ADJ[city])
      {
        if (neighbor.first == 0)
        {
          return neighbor.second;
        }
      }

      return kMaxN * kMaxCost + 1;
    }
  }

  int&amp; ret = CACHE[city][visit];
  if (ret != -1)
  {
    return ret;
  }

  ret = kMaxN * kMaxCost + 1;

  for (const auto&amp; neighbor : ADJ[city])
  {
    int there = neighbor.first;
    int cost = neighbor.second;

    if (visit &amp; (1 &lt;&lt; there))
    {
      continue;
    }

    ret = min(ret, cost + Solve(there, visit | (1 &lt;&lt; there)));
  }

  return ret;
}

int main(void)
{
  // Read inputs
  scanf(&quot; %d&quot;, &amp;N);
  ADJ.assign(N, vector&lt;neighbor_t&gt;());

  for (int u = 0; u &lt; N; ++u)
  {
    for (int v = 0; v &lt; N; ++v)
    {
      int cost;
      scanf(&quot; %d&quot;, &amp;cost);
      if (cost != 0)
      {
        ADJ[u].emplace_back(v, cost);
      }
    }
  }

  // Initialize cache
  for (int city = 0; city &lt; kMaxN; ++city)
  {
    for (int visit = 0; visit &lt; (1 &lt;&lt; kMaxN); ++visit)
    {
      CACHE[city][visit] = -1;
    }
  }

  // Solve
  printf(&quot;%d\n&quot;, Solve(0, 1));

  return 0;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[부분합]]></title>
            <link>https://velog.io/@aram_father/%EB%B6%80%EB%B6%84%ED%95%A9</link>
            <guid>https://velog.io/@aram_father/%EB%B6%80%EB%B6%84%ED%95%A9</guid>
            <pubDate>Wed, 23 Feb 2022 05:18:24 GMT</pubDate>
            <description><![CDATA[<p><strong>Problme link:</strong> <a href="https://www.acmicpc.net/problem/1806">https://www.acmicpc.net/problem/1806</a></p>
<p>같은 위치에서 출발하는 투 포인터를 써준다.</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;algorithm&gt;
#include &lt;vector&gt;
#include &lt;cstdio&gt;

using namespace std;

size_t N;
int64_t S;
vector&lt;int64_t&gt; PSUM;

size_t Solve()
{
  size_t answer = N * 2;

  size_t lo = 1;
  size_t hi = 1;

  while (lo &lt;= hi &amp;&amp; hi &lt;= N)
  {
    int64_t sum = PSUM[hi] - PSUM[lo - 1];
    if (sum &gt;= S)
    {
      answer = min(answer, hi - lo + 1);
      ++lo;
    }
    else
    {
      ++hi;
    }
  }

  return answer &gt; N ? 0 : answer;
}

int main(void)
{
  // For faster IO
  ios_base::sync_with_stdio(false);
  cout.tie(nullptr);
  cin.tie(nullptr);

  // Read input
  cin &gt;&gt; N &gt;&gt; S;
  PSUM.emplace_back(0);

  for (size_t it = 1; it &lt;= N; ++it)
  {
    int64_t number;
    cin &gt;&gt; number;
    PSUM.emplace_back(number + PSUM[it - 1]);
  }

  // Solve
  cout &lt;&lt; Solve() &lt;&lt; &#39;\n&#39;;

  return 0;
}
</code></pre>
]]></description>
        </item>
    </channel>
</rss>