Processing math: 100%

應用:多項式的解數

這邊我們先假設 p=998244353 是個大家最喜歡的質數吧。

第一種想法:利用 NTT

總之 NTT 會帶給你 f(0),f(1),,f(p1) 的值,算完之後就可以知道有幾個解啦。 這個時間複雜度是 O(n+plogp) (吧)

小插曲:利用 NTT 計算多項式乘法

如果要把模 p 底下的兩個多項式 f,g 乘起來,且這兩個多項式的度數都不超過 n。 那麼使用 NTT 我們可以在 O(nlogn) 時間內計算出乘積 fg

第二種想法:兩個多項式的最大公約式

f(x) 在模 p 底下有解 r1,r2,,rt,那麼我們能將 f(x) 寫成形如: f(x)(xr1)k1(xr2)k2(xrt)ktg(x) 的形式,其中 k1,k2,,kt1 為正整數,g(x) 也是一個整係數多項式,而且 g(x) 在模 p 底下毫無整數解。

如果我們將 f(x)h(x):=x(x1)(x2)(x(p1)) 拿去找出最大公約式 (這個在歐幾里德整環來說能夠被良好地定義出來),這個最大公約式就必定會是我們想要的: gcd(f(x),h(x))=(xr1)(xr2)(xrt)

而使用這個方法的好處有兩個:其一,如果我們只在乎 t 的值,那麼找出最大公約式以後,它的次數就會是我們要的答案啦!其二,根據費馬小定理,我們會發現 h(x) 其實根本等於 xpx,非常簡約。 這個簡約的特性,可以讓我們使用反覆平方法或減半平方法加速 gcd(f(x),h(x)) 的第一步的計算!

注意到 (xpx)modf=(xpmodf)(xmodf),我們可以先關心要怎麼計算 xpmodf。 而這就簡單啦:若要計算 xkmodf,可以直接先遞迴求出 (xk/2modf) 之值,然後將之平方然後再取餘數。 (或者是如同 stackoverflow 上面的建議,事先算出 2 的次方除以 f 的餘數,然後再挑你想要的乘起來。) 注意到 n 是多項式 f(x) 的度數。 這邊需要的計算便是兩個最多 n 次多項式的乘法 (我們可以用 NTT 解決它)、以及一個 2n 次多項式除以 n 次多項式的商和餘數。 除法部分的想法基本上來自於 Schönhage,可以參考這份投影片 它給我們的時間複雜度也是 O(nlogn) 的。

於是乎!套用 Knuth-Schönhage 或是 Stehlé-Zimmermann 的每次度數剖半的分而治之法,就能夠給我們一個 O(nlog2n) 總時間的輾轉相除法啦!

參考資料

備註

  • 爆搜的話使用 Chien Search 搭配預處理 Montgomery Multiplication 可以讓實作快非常非常多。雖然是 O(np) 時間但是從頭到尾可以只需要加減法和位元運算。
  • 我寫得爆炸亂...之後有機會再來好好整理...