๐ ์์ธ ์ ๋ฆฌ
- FFT๋ฅผ ์ ๋ชจ๋ฅธ๋ค๋ฉด, ๋จผ์ ์ฝ๊ณ ์ค์.
- ๋คํญ์์ ๊ณฑ์
๊ฒฐ๊ณผ๋ฅผ ํน์ ์์ $p$๋ก ๋๋ ๋๋จธ์ง๋ฅผ ๊ตฌํด์ผํ๊ฑฐ๋, ๊ฐ์ด ์ปค์ง๊ฑฐ๋ ํด์ ์ค์ ์ค์ฐจ๊ฐ ๋ฐ์ํ๋ ๊ฒฝ์ฐ๊ฐ ์๋ค.
- ์ค์๋ฅผ ์์ฐ๊ณ FFT๋ฅผ ํ ์๋ ์์๊น?
- ์ฐ๋ฆฌ๊ฐ FFT์์ ํต์ฌ์ผ๋ก ์ฌ์ฉํ๋ $\omega = \exp\left(-i\dfrac{2\pi}{N}\right)$๋ฅผ ์กฐ๊ธ ๋ ์๊ฐํด๋ณด์.
- FFT์์ ์ฌ์ฉ๋๋ ํต์ฌ์ ์ธ ์ฑ์ง์ $\omega^N = 1$ ์ด๊ณ , $1, \omega, \omega^2, \cdots, \omega^{N-1}$์ด ๋ชจ๋ ๋ค๋ฅด๋ค๋ ์ ์ด๋ค.
- ๊ทธ๋ฌ๋ฉด ๋ชจ๋๋ฌ ํฉ๋์์ ๊ด์ ์์, ์ด๋ค ์ $k$์ ์ด๋ค ์์ $p$๊ฐ ์์ด์ $k^N \equiv 1 \pmod p$๋ฅผ ๋ง์กฑ์ํค๊ณ , $1, g, g^2, \cdots, g^{N-1} \pmod p$์ด ๋ชจ๋ ๋ค๋ฅด๋ค๋ฉด, FFT์ ๊ฐ์ ๋๋์ผ๋ก ์ฌ์ฉํ ์ ์์ง ์์๊น?
- ์ด๋ฌํ ์ $g$๋ฅผ ์์๊ทผ์ด๋ผ๊ณ ํ๋ค.
- ๊ทธ๋ฌ๋ฉด $N$์ ๋ ์ ์ก์์ผํ ๊ฒ ๊ฐ์๋ฐ, ํ๋ฅด๋ง์ ์์ ๋ฆฌ๋ฅผ ์ด์ฉํ ์ ์์ ๊ฒ ๊ฐ๋ค.
- $a^{p-1} \equiv 1 \pmod p$ ์ด๋ฏ๋ก, $N = p-1$์ด๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค.
- FFT๋ฅผ ๋ฐ์ผ๋ก ์ชผ๊ฐ๋ ๋ฐฉ๋ฒ์ ์ ์ด์ฉํ๊ธฐ ์ํด์ , $N$์ด $2$๋ก ์ถฉ๋ถํ ๋ง์ด ๋๋์ด ๋จ์ด์ง๋ฉด ์ข๊ฒ ๋ค.
- $N = a \times 2^b$ ๊ผด์ด๋ฉด ์ข๊ฒ ๊ณ , ์ด์ ๋ฐ๋ผ $p = a \times 2^b + 1$ ์ด๋ฉด ์ข๊ฒ ๋ค.
- $N$์ $2$๋ก ๋๋์ด ๋จ์ด์ง๊ฒ ํ ์ ์๋ ํ์์ ๋ฐ๋ผ FFT๋ก ๊ณ์ฐ ๊ฐ๋ฅํ ๋ฐฐ์ด์ ํฌ๊ธฐ๊ฐ ๋ฌ๋ผ์ง๋ค!
- $n \leq 2^b$ ์ ํฌ๊ธฐ์ ๋คํญ์๊น์ง๋ง ๊ฐ๋ฅํ๋ค.
- ์ด๋ก ์ด์ธ๋ฆฌ๋ ๋ํ์ ์ธ ์์๋ก๋ $p = 998244353 = 119 \times 2^{23} + 1$ ์ด ์๊ฒ ๋ค.
- ์ด๋ ์์๊ทผ $g = 3$ ์ ์ฌ์ฉํ ์ ์๋ค.
- ๊ทธ๋ฌ๋ฉด ์ด์ $\omega = \exp\left(-i\dfrac{2\pi}{N}\right)$ ๋์ $\omega = g^{(p-1)/n}$ ์ ์ด์ฉํด์ FFT๋ฅผ ์ํํ ์ ์๊ฒ ๋์๋ค.
- ์ด๋ฅผ ๊ตฌํํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
void ntt(vector<mint> &a, bool inv = false){
int N = a.size();
assert(N > 0 && (N & (N-1)) == 0); // N์ 2์ ๊ฑฐ๋ญ์ ๊ณฑ์ด์ด์ผ ํจ
// ๋นํธ ๋ค์ง๊ธฐ
for(int i = 1, j = 0; i < N; i++){
int bit = N >> 1;
for(; j & bit; bit >>= 1) j ^= bit;
j ^= bit;
if(i < j) swap(a[i], a[j]);
}
// ๋จ์๊ทผ ๋ฏธ๋ฆฌ ๊ณ์ฐ
mint ang = mint(3).pow((MOD-1)/N);
if(inv) ang = ang.inv();
vector<mint> w(N/2); // ๋จ์๊ทผ
w[0] = 1;
rep(i, 1, N/2) w[i] = w[i-1] * ang;
// Cooley-Tukey FFT
for(int len = 2; len <= N; len <<= 1){
int step = N / len;
for(int i = 0; i < N; i += len){
rep(j, 0, len>>1){
mint even = a[i+j], odd = a[i+j+(len>>1)] * w[j*step];
a[i+j] = even + odd;
a[i+j+(len>>1)] = even - odd;
}
}
}
// ์ญ FFT์ธ ๊ฒฝ์ฐ ๊ฒฐ๊ณผ๋ฅผ N์ผ๋ก ๋๋
if(inv){
mint invN = mint(N).inv();
rep(i, 0, N) a[i] *= invN;
}
}
โ์ง๋ฌธ ์ฌํญ
๐ ์ฐธ๊ณ ์๋ฃ