設參與運算的多項式最高次數是n,那么多項式的加法,減法顯然可以在O(n)時間內計算。
所以我們關心的是兩個多項式的乘積。朴素的方法需要O(n^2)時間,並不夠優秀。
考慮優化。
多項式乘積
方案一:分治乘法。
對於多項式X,Y,假設各有2m項,(即最高次數是2m-1)
X,Y分別可以用兩個含m項的多項式來表示,即:
則
由此可見,為了計算XY,只需計算出AC, (A+B)(C+D), BD,然后用多項式加減法求得XY即可。
設含有m項的多項式相乘的時間為T(m)
則
於是容易算出時間復雜度是,約等於
以上方法的優點在於,代碼難度低,思維難度低,多項式系數任意,對運算沒有任何限制。
缺點在於:太慢了!
方案二:FFT / NTT
這種方法除了快之外,沒有任何優點。但仍是一種好方法。
FFT的詳細推導不再描述,這里只是簡單的總結。
對於多項式乘法,有一種思路,
a. 是先從系數表示法轉換為點值表示法,
b. 然后乘起來(得到乘積式的點值表示法),
c. 最后從點值表示法轉變回系數表示法。
對於操作a,很容易做到O(n^2),
對於操作b,很容易做到O(n),
對於操作c,用高斯消元可以做到O(n^3),用拉格朗日插值法可以做到O(n^2)。
FFT則是利用了單位根的性質,將操作a和操作c優化到了O(nlogn)。
雖然在復數域中永遠存在單位根,但是容易出現精度問題。
NTT並沒有用復數域的單位根。
當某兩個多項式相乘,系數對某一模數取模的時候,必須存在2^k次(2^k>=2n)單位根,且必須存在2的逆元。
當模數p是形如 998244353 的質數時,998244353 = 7 × 17 × 2^23 + 1,( 2^k | phi(p) )
設p的原根是g,則模p意義下,2^k次單位根是 。
當模數並不是滿足要求的模數,我們可以知道,一次多項式乘法的結果,每一位上的數不超過n*p*p。
我們可以取多個不同的NTT模數,使得它們的乘積大於n*p*p。對每一個NTT模數做一次多項式乘法,最后用中國剩余定理計算即可。
多項式求逆
我們定義多項式A的乘法逆元B,滿足A*B=1。
多項式求逆能解決多項式除法等一系列問題,因為X/Y=X*Y的逆元。
我們首先證明,多項式A存在乘法逆元的充要條件是A的常系數存在逆元。
必要性顯然,因為A的常數項*B的常數項=1。
由此,我們可以求出B的常數項,接着推出一次項系數,二次項系數...
所以乘法逆元存在且唯一,充分性同樣顯然。
為了求逆元,一種方法是O(n^2),即先求常數項,再推出一次項系數,繼續推完整個多項式。
還有一種用O(nlogn)時間計算乘法逆元的方法,
先求出A(x)的常數項的逆元b,初始化B(x)=b,則