<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Algorithm Topics on Jiho Kim</title><link>https://blog.wlgh7407.com/posts/algorithm/topics/</link><description>Recent content in Algorithm Topics on Jiho Kim</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>© 2026 Jiho Kim</copyright><lastBuildDate>Mon, 06 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.wlgh7407.com/posts/algorithm/topics/index.xml" rel="self" type="application/rss+xml"/><item><title>NTT(Number Theoretic Transform) - 정수론적 변환</title><link>https://blog.wlgh7407.com/posts/algorithm/topics/260406_til_nttnumber-theoretic-transform---%EC%A0%95%EC%88%98%EB%A1%A0%EC%A0%81-%EB%B3%80%ED%99%98/</link><pubDate>Mon, 06 Apr 2026 00:00:00 +0000</pubDate><guid>https://blog.wlgh7407.com/posts/algorithm/topics/260406_til_nttnumber-theoretic-transform---%EC%A0%95%EC%88%98%EB%A1%A0%EC%A0%81-%EB%B3%80%ED%99%98/</guid><description>&lt;h2 class="relative group"&gt;📝 상세 정리
 &lt;div id="-상세-정리" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#-%ec%83%81%ec%84%b8-%ec%a0%95%eb%a6%ac" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.wlgh7407.com/posts/algorithm/topics/260402_til_fft---%EA%B3%A0%EC%86%8D-%ED%91%B8%EB%A6%AC%EC%97%90-%EB%B3%80%ED%99%98/" &gt;FFT&lt;/a&gt;를 잘 모른다면, 먼저 읽고 오자.&lt;/li&gt;
&lt;li&gt;다항식의 곱셈 결과를 특정 소수 $p$로 나눈 나머지를 구해야하거나, 값이 커지거나 해서 실수 오차가 발생하는 경우가 있다.
&lt;ul&gt;
&lt;li&gt;실수를 안쓰고 FFT를 할 수는 없을까?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;우리가 FFT에서 핵심으로 사용하던 $\omega = \exp\left(-i\dfrac{2\pi}{N}\right)$를 조금 더 생각해보자.
&lt;ul&gt;
&lt;li&gt;FFT에서 사용되는 핵심적인 성질은 $\omega^N = 1$ 이고, $1, \omega, \omega^2, \cdots, \omega^{N-1}$이 모두 다르다는 점이다.&lt;/li&gt;
&lt;li&gt;그러면 모듈러 합동식의 관점에서, 어떤 수 $k$와 어떤 소수 $p$가 있어서 $k^N \equiv 1 \pmod p$를 만족시키고, $1, g, g^2, \cdots, g^{N-1} \pmod p$이 모두 다르다면, FFT와 같은 느낌으로 사용할 수 있지 않을까?
&lt;ul&gt;
&lt;li&gt;이러한 수 $g$를 &lt;strong&gt;원시근&lt;/strong&gt;이라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;그러면 $N$을 또 잘 잡아야할 것 같은데, 페르마의 소정리를 이용할 수 있을 것 같다.&lt;/li&gt;
&lt;li&gt;$a^{p-1} \equiv 1 \pmod p$ 이므로, $N = p-1$이면 좋을 것 같다.&lt;/li&gt;
&lt;li&gt;FFT를 반으로 쪼개던 방법을 잘 이용하기 위해선, $N$이 $2$로 충분히 많이 나누어 떨어지면 좋겠다.
&lt;ul&gt;
&lt;li&gt;$N = a \times 2^b$ 꼴이면 좋겠고, 이에 따라 $p = a \times 2^b + 1$ 이면 좋겠다.
&lt;ul&gt;
&lt;li&gt;$N$을 $2$로 나누어 떨어지게 할 수 있는 횟수에 따라 FFT로 계산 가능한 배열의 크기가 달라진다!&lt;/li&gt;
&lt;li&gt;$n \leq 2^b$ 의 크기의 다항식까지만 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이로 어울리는 대표적인 소수로는 $p = 998244353 = 119 \times 2^{23} + 1$ 이 있겠다.
&lt;ul&gt;
&lt;li&gt;이때 원시근 $g = 3$ 을 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;그러면 이제 $\omega = \exp\left(-i\dfrac{2\pi}{N}\right)$ 대신 $\omega = g^{(p-1)/n}$ 을 이용해서 FFT를 수행할 수 있게 되었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이를 구현하면 다음과 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ntt&lt;/span&gt;(vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;mint&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;a, &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; inv &lt;span style="color:#f92672"&gt;=&lt;/span&gt; false){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; N &lt;span style="color:#f92672"&gt;=&lt;/span&gt; a.size();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	assert(N &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; (N &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; (N&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)) &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// N은 2의 거듭제곱이어야 함
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// 비트 뒤집기
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, j &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; N; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; bit &lt;span style="color:#f92672"&gt;=&lt;/span&gt; N &lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(; j &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; bit; bit &lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) j &lt;span style="color:#f92672"&gt;^=&lt;/span&gt; bit;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		j &lt;span style="color:#f92672"&gt;^=&lt;/span&gt; bit;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; j) swap(a[i], a[j]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// 단위근 미리 계산
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	mint ang &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mint(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;).pow((MOD&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)&lt;span style="color:#f92672"&gt;/&lt;/span&gt;N);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(inv) ang &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ang.inv();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;mint&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; w(N&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 단위근
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	w[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	rep(i, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, N&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) w[i] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; w[i&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;*&lt;/span&gt; ang;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// Cooley-Tukey FFT
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; len &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;; len &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; N; len &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; step &lt;span style="color:#f92672"&gt;=&lt;/span&gt; N &lt;span style="color:#f92672"&gt;/&lt;/span&gt; len;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; N; i &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; len){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			rep(j, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, len&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				mint even &lt;span style="color:#f92672"&gt;=&lt;/span&gt; a[i&lt;span style="color:#f92672"&gt;+&lt;/span&gt;j], odd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; a[i&lt;span style="color:#f92672"&gt;+&lt;/span&gt;j&lt;span style="color:#f92672"&gt;+&lt;/span&gt;(len&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)] &lt;span style="color:#f92672"&gt;*&lt;/span&gt; w[j&lt;span style="color:#f92672"&gt;*&lt;/span&gt;step];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				a[i&lt;span style="color:#f92672"&gt;+&lt;/span&gt;j] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; even &lt;span style="color:#f92672"&gt;+&lt;/span&gt; odd;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				a[i&lt;span style="color:#f92672"&gt;+&lt;/span&gt;j&lt;span style="color:#f92672"&gt;+&lt;/span&gt;(len&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; even &lt;span style="color:#f92672"&gt;-&lt;/span&gt; odd;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// 역 FFT인 경우 결과를 N으로 나눔
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(inv){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		mint invN &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mint(N).inv();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		rep(i, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, N) a[i] &lt;span style="color:#f92672"&gt;*=&lt;/span&gt; invN;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 class="relative group"&gt;❔질문 사항
 &lt;div id="질문-사항" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%ec%a7%88%eb%ac%b8-%ec%82%ac%ed%95%ad" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;🔗 참고 자료
 &lt;div id="-참고-자료" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#-%ec%b0%b8%ea%b3%a0-%ec%9e%90%eb%a3%8c" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://rkm0959.tistory.com/187" target="_blank" rel="noreferrer"&gt;https://rkm0959.tistory.com/187&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://algoshitpo.github.io/2020/05/20/fft-ntt/" target="_blank" rel="noreferrer"&gt;https://algoshitpo.github.io/2020/05/20/fft-ntt/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>FFT - 고속 푸리에 변환</title><link>https://blog.wlgh7407.com/posts/algorithm/topics/260402_til_fft---%EA%B3%A0%EC%86%8D-%ED%91%B8%EB%A6%AC%EC%97%90-%EB%B3%80%ED%99%98/</link><pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate><guid>https://blog.wlgh7407.com/posts/algorithm/topics/260402_til_fft---%EA%B3%A0%EC%86%8D-%ED%91%B8%EB%A6%AC%EC%97%90-%EB%B3%80%ED%99%98/</guid><description>&lt;h2 class="relative group"&gt;📝 상세 정리
 &lt;div id="-상세-정리" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#-%ec%83%81%ec%84%b8-%ec%a0%95%eb%a6%ac" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;이제 슬슬 FFT를 이해할 때가 된것 같다. 정리해보자.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;푸리에 변환
 &lt;div id="푸리에-변환" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%ed%91%b8%eb%a6%ac%ec%97%90-%eb%b3%80%ed%99%98" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;여러 사인파 / 코사인파가 더해진 함수 $h(t)$가 있다.
&lt;ul&gt;
&lt;li&gt;일단 먼저 사인파만 있다고 가정해보자.&lt;/li&gt;
&lt;li&gt;우리는 이 함수 $h(t)$에서 어떤 주파수를 가진 성분들이 있는지 검사하고싶다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;더 쉽게, 먼저 사인파 하나에 대해서 생각해보자.
&lt;ul&gt;
&lt;li&gt;함수 $f(x) = \sin{ax}$가 있다.
&lt;ul&gt;
&lt;li&gt;우리는 $a$를 모른다고 가정하자.&lt;/li&gt;
&lt;li&gt;어떻게 하면 이 $a$를 알아낼 수 있을까?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;임의의 사인파 $g(x) = \sin{bx}$를 곱해보자.
&lt;ul&gt;
&lt;li&gt;삼각함수의 곱셈정리에 의해&lt;/li&gt;
&lt;li&gt;$f(x)g(x) = \sin{ax}\sin{bx} = \frac{\cos{((a-b)x)} - \cos{((a+b)x)}}{2}$
&lt;ul&gt;
&lt;li&gt;위와 같이 나타낼 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이를 음의 무한대부터 양의 무한대까지 적분하면, 주기함수의 특성을 이용해서 $a, b$가 같은지 다른지 알아낼 수 있다.
&lt;ul&gt;
&lt;li&gt;$a, b$는 주파수기에 $a, b &gt; 0$이 보장된다.&lt;/li&gt;
&lt;li&gt;$a = b$일 때만 양의 무한대로 발산하고, 그 외의 경우 진동발산한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;위의 특징은 여러 사인파의 합 $h(t)$에 대해서도 간단하게 성립한다.&lt;/li&gt;
&lt;li&gt;코사인 파가 섞여있다면 코사인파를 곱해서 같은 방법으로 수행해주면 되겠다.&lt;/li&gt;
&lt;li&gt;이 때, 오일러 공식 $e^{ix} = \cos{x} + i\sin{x}$을 이용해서 실수부 / 허수부로 나눠서 더 쉽게 계산할 수도 있다.&lt;/li&gt;
&lt;li&gt;이를 식으로 나타내면 다음과 같다.
&lt;ul&gt;
&lt;li&gt;$$\hat{h}(x) = \int_{-\infty}^{\infty}{h(t)e^{-2\pi itx}dt}$$&lt;/li&gt;
&lt;li&gt;이는 신호 -&amp;gt; 주파수로의 변환으로 해석하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;반대로 주파수 -&amp;gt; 신호의 변환도 가능하다.
&lt;ul&gt;
&lt;li&gt;$$h(t) = \int_{-\infty}^{\infty}{\hat{h}(x)e^{2\pi itx}dx}$$&lt;/li&gt;
&lt;li&gt;이를 푸리에 역변환이라고 하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;여기서 갖고 놀아보자. 이해할때 클로드가 만들어줬다.
&lt;div class="fv-wrap"&gt;
 &lt;style&gt;
 .fv-wrap {
 background: transparent;
 color: #e0e0e0;
 font-family: "Segoe UI", sans-serif;
 margin: 1.5rem 0;
 }
 .fv-wrap .fv-controls {
 display: flex;
 gap: 12px;
 flex-wrap: wrap;
 align-items: center;
 margin-bottom: 12px;
 padding: 10px 12px;
 background: #1a1d27;
 border-radius: 8px;
 }
 .fv-wrap .fv-controls label {
 font-size: 0.78rem;
 color: #aaa;
 }
 .fv-wrap .fv-controls select {
 background: #252836;
 color: #e0e0e0;
 border: 1px solid #333;
 border-radius: 4px;
 padding: 4px 8px;
 font-size: 0.8rem;
 }
 .fv-wrap .fv-section {
 margin-bottom: 16px;
 background: #1a1d27;
 border-radius: 8px;
 overflow: hidden;
 }
 .fv-wrap .fv-section-title {
 color: #7eb8f7;
 font-size: 0.85rem;
 font-weight: 600;
 padding: 8px 12px 2px;
 margin: 0;
 border: none;
 }
 .fv-wrap .fv-section-desc {
 color: #666;
 font-size: 0.75rem;
 padding: 0 12px 6px;
 margin: 0;
 }
 .fv-wrap canvas {
 width: 100%;
 height: 160px;
 display: block;
 }
 &lt;/style&gt;

 &lt;div class="fv-controls"&gt;
 &lt;label&gt;신호 종류: &lt;/label&gt;
 &lt;select id="fv-signalType"&gt;
 &lt;option value="finite_sine"&gt;유한 사인파 (현실적)&lt;/option&gt;
 &lt;option value="two_freq"&gt;두 주파수 합성&lt;/option&gt;
 &lt;option value="square"&gt;구형파&lt;/option&gt;
 &lt;option value="infinite_sine"&gt;무한 사인파 (이상적)&lt;/option&gt;
 &lt;/select&gt;
 &lt;/div&gt;

 &lt;div class="fv-section"&gt;
 &lt;p class="fv-section-title"&gt;① 시간 도메인 — h(t)&lt;/p&gt;</description></item><item><title>SOS Dynamic Programming</title><link>https://blog.wlgh7407.com/posts/algorithm/topics/260222_til_sos-dp/</link><pubDate>Sun, 22 Feb 2026 00:00:00 +0000</pubDate><guid>https://blog.wlgh7407.com/posts/algorithm/topics/260222_til_sos-dp/</guid><description>&lt;h2 class="relative group"&gt;📝 상세 정리
 &lt;div id="-상세-정리" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#-%ec%83%81%ec%84%b8-%ec%a0%95%eb%a6%ac" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;$2^N$개의 정수 배열 $A$가 주어진다. 이때 $\forall x$ 에 대해 $F(x)$를 $\sum\limits_{i \subseteq x}{A[i]}$ 라고 정의하자. 이는 $x\&amp;i = i$ 인 $i$들에 대해 $A[i]$의 합을 의미한다.&lt;/li&gt;
&lt;li&gt;위와 같은 문제를 어떻게 풀 수있을까?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;브루트포스
 &lt;div id="브루트포스" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%eb%b8%8c%eb%a3%a8%ed%8a%b8%ed%8f%ac%ec%8a%a4" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;느리지만, 다음과 같은 브루트포스로 계산할 수 있겠다.
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; mask &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; mask &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt;N); mask&lt;span style="color:#f92672"&gt;++&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt;N); i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;((mask&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;i) &lt;span style="color:#f92672"&gt;==&lt;/span&gt; i){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			F[mask] &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; A[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;위 식을 그대로 옮긴 것에 가깝다.&lt;/li&gt;
&lt;li&gt;시간복잡도는 ${(2^N)}^2 = 4^N$이다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;조금 더 나은 풀이
 &lt;div id="조금-더-나은-풀이" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%ec%a1%b0%ea%b8%88-%eb%8d%94-%eb%82%98%ec%9d%80-%ed%92%80%ec%9d%b4" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;두번째 반복문에 대해, 바깥쪽 반복문에서 켜지지 않은 비트에 대해서도 반복을 도는것은 너무 아깝다.&lt;/li&gt;
&lt;li&gt;따라서 다음과 같이도 한번 시도해볼 수 있겠다.
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; mask &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; mask &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt;N); mask&lt;span style="color:#f92672"&gt;++&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	F[mask] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; A[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt;N); i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (i&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask) F[mask] &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; A[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;시간복잡도 증명이 어려워보인다.&lt;/li&gt;
&lt;li&gt;이는 $\sum\limits_{k = 0}^N{\binom{N}{K}2^K} = 3^N$ 이라고 한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;Sum over Subsets DP
 &lt;div id="sum-over-subsets-dp" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#sum-over-subsets-dp" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;위의 방식에서 병목은 어디에서 나타날까?&lt;/li&gt;
&lt;li&gt;어떤 $x$의 비트가 $K$개가 꺼져있을 때, $A[x]$는 $2^K$개의 마스크에 의해 방문된다.
&lt;ul&gt;
&lt;li&gt;이 반복적인 재계산을 줄여야한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 class="relative group"&gt;S(mask, i) 정의
 &lt;div id="smask-i-정의" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#smask-i-%ec%a0%95%ec%9d%98" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;위 병목을 피하기 위해 새로운 상태를 하나 정의해보자.&lt;/li&gt;
&lt;li&gt;$S(mask, i)$는 $mask$의 &lt;strong&gt;부분집합&lt;/strong&gt;들 중, $mask$와 하위(오른쪽) $i$개 비트(0~i-1번 인덱스)에서만 다른 것을 의미한다.&lt;/li&gt;
&lt;li&gt;예를 들어, $S(110, 2) = \{100, 110\}$이다. 오른쪽 두개 비트에서 다를 수 있는데, 부분집합이어야 하므로 $111$같은건 안된다.&lt;/li&gt;
&lt;li&gt;이 정의를 이용하면, 어떤 집합도 서로 겹치지 않는 $S(mask, i)$들의 합집합으로 나타낼 수 있게 된다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 class="relative group"&gt;점화식 유도
 &lt;div id="점화식-유도" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%ec%a0%90%ed%99%94%ec%8b%9d-%ec%9c%a0%eb%8f%84" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;점화식은 다음과 같이 두가지로 정의할 수 있겠다.&lt;/li&gt;
&lt;li&gt;$mask$의 $i$번째 비트가 $0$인 경우
&lt;ul&gt;
&lt;li&gt;$mask$의 부분집합이 $i$번째 비트에서 $0$만을 가질 수 있으므로&lt;/li&gt;
&lt;li&gt;$S(mask, i) = S(mask, i-1)$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;$mask$의 $i$번째 비트가 $1$인 경우
&lt;ul&gt;
&lt;li&gt;$mask$의 부분집합이 $i$번째 비트에서 $0, 1$ 모두 가질 수 있으므로&lt;/li&gt;
&lt;li&gt;$S(mask, i) = S(mask, i-1) \cup S(mask \oplus 2^i, i-1)$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;따라서 이를 코드로 나타내면 다음과 같다.
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; mask &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; mask &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt;N); mask&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) DP[mask] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; A[mask];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;N; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; mask &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; mask &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt;N); mask&lt;span style="color:#f92672"&gt;++&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(mask &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt;i)) DP[mask] &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; DP[mask &lt;span style="color:#f92672"&gt;^&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt;i)];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;계산 결과 DP에 들어있는 값은 해당 비트마스킹의 부분집합의 합이다.&lt;/li&gt;
&lt;li&gt;시간복잡도는 그대로 보이듯이 $O(N2^N)$이다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;N차원 누적합
 &lt;div id="n차원-누적합" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#n%ec%b0%a8%ec%9b%90-%eb%88%84%ec%a0%81%ed%95%a9" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.queuedlab.com/posts/sos-dp" target="_blank" rel="noreferrer"&gt;https://blog.queuedlab.com/posts/sos-dp&lt;/a&gt; 를 참고하면, 이를 $N$차원 누적합으로도 해석할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.wlgh7407.com/posts/algorithm/ps/260204_algorithm_boj-18830-%ED%95%98%EC%9D%B4%ED%8D%BC-%EC%88%98%EC%97%B4%EA%B3%BC-%ED%95%98%EC%9D%B4%ED%8D%BC-%EC%BF%BC%EB%A6%AC/" &gt;하이퍼 수열과 하이퍼 쿼리&lt;/a&gt; 문제에서 $N$차원 누적합 아이디어는 써본적이 있었는데, 이것이 SOS DP와 같다는 것이 신기하다.&lt;/li&gt;
&lt;li&gt;앞으로는 포함배제에서 뭔가 줄이고싶으면 한번씩은 의심해보는걸로?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;imos-hanbyul Trick
 &lt;div id="imos-hanbyul-trick" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#imos-hanbyul-trick" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;이와 비슷한 내용을 &lt;a href="https://qwerasdfzxcl.tistory.com/35" target="_blank" rel="noreferrer"&gt;https://qwerasdfzxcl.tistory.com/35&lt;/a&gt; 여기서 본적이 있다.&lt;/li&gt;
&lt;li&gt;지금 당장은 이해하기 귀찮으므로 이해한 내용은 나중에 추가하겠다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;❔질문 사항
 &lt;div id="질문-사항" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%ec%a7%88%eb%ac%b8-%ec%82%ac%ed%95%ad" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;🔗 참고 자료
 &lt;div id="-참고-자료" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#-%ec%b0%b8%ea%b3%a0-%ec%9e%90%eb%a3%8c" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://codeforces.com/blog/entry/45223" target="_blank" rel="noreferrer"&gt;https://codeforces.com/blog/entry/45223&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.queuedlab.com/posts/sos-dp" target="_blank" rel="noreferrer"&gt;https://blog.queuedlab.com/posts/sos-dp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://qwerasdfzxcl.tistory.com/35" target="_blank" rel="noreferrer"&gt;https://qwerasdfzxcl.tistory.com/35&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Approximate Nearest Nighbor 알고리즘</title><link>https://blog.wlgh7407.com/posts/algorithm/topics/260127_til_approximate-nearest-nighbor-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98/</link><pubDate>Tue, 27 Jan 2026 00:00:00 +0000</pubDate><guid>https://blog.wlgh7407.com/posts/algorithm/topics/260127_til_approximate-nearest-nighbor-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98/</guid><description>&lt;h2 class="relative group"&gt;📝 상세 정리
 &lt;div id="-상세-정리" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#-%ec%83%81%ec%84%b8-%ec%a0%95%eb%a6%ac" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;주어진 쿼리포인트와 매우 가까운 데이터 포인트를 찾는 알고리즘&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;기본적으로는 모든 노드에 대해 확인해봐야하므로 $O(N)$이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;KD-Trees&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Locality-Sensitive Hashing (LSH)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Annoy (Approximate Nearest Neighbors Oh Yeah)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Linear Scan Algorithm&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이건 선형이자나 머야&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;❔질문 사항
 &lt;div id="질문-사항" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%ec%a7%88%eb%ac%b8-%ec%82%ac%ed%95%ad" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;🔗 참고 자료
 &lt;div id="-참고-자료" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#-%ec%b0%b8%ea%b3%a0-%ec%9e%90%eb%a3%8c" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dytis.tistory.com/108" target="_blank" rel="noreferrer"&gt;https://dytis.tistory.com/108&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>