多項式乘法為什麼要繞一圈去頻域算?因為頻域裡乘法是 O(n),轉換的代價比直接算還小。

問題:大數/多項式乘法的瓶頸

兩個 n 次多項式相乘,係數對係數直接算是 O(n²)。兩個 n 位大數相乘同理——高中乘法。

n = 10^6 時,O(n²) = 10^12,絕對超時。

FFT 的突破:換一種表示法,讓乘法變簡單。

兩種多項式表示法

係數表示:A(x) = a₀ + a₁x + a₂x² + ... + aₙxⁿ
  → 兩個 n 次多項式相乘,直接算需要 O(n²)

點值表示:用 n+1 個「(輸入, 輸出)」對唯一確定多項式
  A 的點值 × B 的點值 = (A×B) 的點值
  → 逐點相乘,O(n)

關鍵問題:怎麼在係數表示和點值表示之間快速轉換?

單位根讓轉換快起來

選 n 個特殊的輸入點——n 次單位根(ω, ω², ω³, …, ωⁿ = 1):

ωₙ = e^(2πi/n) = cos(2π/n) + i×sin(2π/n)

特殊性質:ωₙ^(k+n/2) = -ωₙ^k   (消去引理)

有了這個性質,可以把 n 點 DFT 拆成兩個 n/2 點 DFT:

A(x) = A_even(x²) + x × A_odd(x²)

A[k]       = A_even[k] + ω^k × A_odd[k]   (蝴蝶操作)
A[k + n/2] = A_even[k] - ω^k × A_odd[k]

每層 n 次操作,共 log n 層,總 O(n log n)。

完整流程

多項式乘法(A × B):

1. FFT(A 的係數) → A 在 n 個單位根的點值
2. FFT(B 的係數) → B 在 n 個單位根的點值
3. 逐點相乘 → (A×B) 的點值,O(n)
4. IFFT(逆變換) → (A×B) 的係數

IFFT = FFT 的共軛版本 + 除以 n

競程中的 NTT(數論變換)

FFT 用複數浮點運算,精度問題在競程中很麻煩(係數可能是整數,要求精確答案)。

NTT 用模質數的整數單位根,避免浮點——競程標準做法,模數通常選 998244353(= 119 × 2²³ + 1,保證 2²³ 次方的 NTT 可行)。

哪裡用到?

  • 大數乘法:n 位 × n 位,O(n log n)
  • 字串匹配(卷積匹配):模式中有通配符時,轉成多項式乘法
  • 「差為 k 的點對數量」:兩個頻率陣列的卷積
  • 圖像處理:高斯模糊、銳化等濾波操作底層是卷積,卷積用 FFT 加速

FFT 的精髓是:在時域做乘法很貴,去頻域後乘法免費——轉換的代價 O(n log n) 比直接算 O(n²) 更值得付。