多項式 學習筆記

2022-05-31 03:48:10 字數 3297 閱讀 2651

已知兩個多項式的係數表示式,求其乘積的係數表示式。

\[c_n = \sum\limits_^a_ib_

\]係數表示式逐項相乘,複雜度\(o(n^2)\),而點值表示式相乘複雜度為\(o(n)\)。因此我們要快速地將兩個多項式轉化為點值表示式,完成點值表示式的乘法,然後轉為係數表示式得到結果。表示式轉換的過程分別是離散傅利葉變換(\(dft\))和離散傅利葉逆變換(\(idft\))。這兩個過程統稱為快速傅利葉變換(\(fft\))。

目標:快速求得係數表示式對應的點值表示式。

設有多項式

\[a(x)=a_0+a_1x+a_2x^2+...+a_x^

\]其中\(n\)為2的冪,不足則補0。我們按照其指數的奇偶將其分為兩部分,變成兩個新多項式。

\[a_1(x)=a_0+a_2x+...+a_x^-1}

\]\[a_2(x)=a_1+a_3x+...+a_x^-1}

\]則有\(a(x)=a_1(x^2)+xa_2(x^2)\)

單位根

在復平面內以原點為圓心,半徑為1的圓稱為單位圓。以\((1,0)\)為起點,將單位圓\(n\)等分,這些等分點是\(n\)個單位根。記第乙個單位根為\(\omega_n\),根據複數相乘模長相乘,幅角相加的原則,第\(k\)個單位根記作\(\omega_n^k\)。

根據三角函式推得單位根的表示方法:\(\omega_n^k=cos\frac+isin\frac\)

定理一(相消定理,折半引理):\(\omega_^=\omega_n^k,\omega_n^k=\omega_}^}\)

定理二:\(\omega_n^k=-\omega_n^}\)

我們選擇將單位根帶入這兩個子多項式求點值。

設\(k<\dfrac\),將任意\(\omega_n^k\)代入\(a(x)\)可得$$a(\omega_nk)=a_1(\omega_})+\omega_nka_2(\omega_}k)$$

將任意\(\omega_n^}\)代入\(a(x)\)可得$$a(\omega_n})=a_1(\omega_})-\omega_nka_2(\omega_}k)$$

所以只要求出\(a_1(\omega_}^)\)和\(a_2(\omega_}^k)\),就可以求得\(a(\omega_n^k)\)和\(a(\omega_n^})\)。也就是說,\(k\)只要取\([0,\frac)\)就可以得出另一半\([\frac,n)\)。因此就得到了整個區間\([0,n)\),也就求出了\(a(x)\)的點值表示式。

遞迴求解即可,複雜度\(o(n \log n)\)

目標:將點值表示式轉化回係數表示式

設點值表示式乘法結果為\((y_0,y_1,...,y_)\)。設它對應的係數表示式(答案)為\((a_0,a_1,...,a_)\)

我們構造乙個以\((y_0,y_1,...,y_)\)為係數的多項式

\[b(x)=y_0+y_1x+...+y_x^

\]此時多項式\(b(x)\)是係數表示的。我們依次將單位根的倒數(\(\omega_n^0,\omega_n^,...,\omega_n^\))代入得到乙個點值表示式\((z_0,z_1,...,z_)\)。

\[\begin z_k &= \sum_^y_i(\omega_n^)^i\\ &= \sum_^(\sum_^a_j*\omega_n^)(\omega_n^)^i\\ &= \sum_^\sum_^a_j*(\omega_n^)^i\\ &= \sum_^a_j(\sum_^(\omega_n^)^i)\\ \end

\]而因為後半部分\(\sum_^(\omega_n^)^i\)可由等比數列求和公式得:

\[\sum_^(\omega_n^)^i=\dfrac)^n-1}-1}

\]注意,要使此式有意義,需滿足分母不為0。而當\(j=k\)時分母為0。因此分類討論:

當\(j \neq k\)時,\(\sum_^(\omega_n^)^i=0\)。

當\(j = k\)時,\(\sum_^(\omega_n^)^i=n\)

綜上\[z_k = \sum\limits_^a_j(\sum\limits_^(\omega_n^)^i) = na_k

\]所以

\[a_k=\dfrac

\]因此我們只需要把我們得到的點值表示式看做是係數表示式,再做一次\(dft\)(其中單位根以倒數形式代入)就能夠得到我們所要的結果了。最後還要除以\(n\)。

剛才這樣是通過遞迴實現的,常數較大。

如果能事先確定葉節點的值,就可以直接向上合併了。之前係數是按照奇偶分左右的。第\(i\)層的分配看二進位制的倒數第\(i\)位……因此係數的位置就是其初始位置的二進位制倒序。

當前這一輪我們需要利用兩個點值\(a_1(\omega_}^)\)和\(a_2(\omega_}^k)\),我們利用他們造出了\(a(\omega_n^k)\)並推出了\(a(\omega_n^})\),恰好可以把它們儲存到原來的位置。這就是所謂的「蝴蝶操作」。

\(fft\)需要用複數運算,存在精度問題。\(ntt\)(快速數論變換)是模意義下的\(fft\),可以避免精度問題,還快了不少。而其實現原理就是用模數的原根來代替單位根。

設模數\(p\)的原根為\(g\),根據費馬小定理我們知道\(g^ \equiv 1 (\text p)\)。\(n\)個原根是\(g^*k}\)。這就要求\(n\)是\(p-1\)的因數,而\(n\)又是\(2\)的冪。\(998244353\)就是這樣乙個滿足條件的模數,它的原根是\(3\)。對於其他的模數,這裡有。

/*dennyqi 2019*/

#include #include #include #include using namespace std;

const int n = 4000010;

const int p = 998244353;

const int inf = 0x3f3f3f3f;

inline int max(const int& a, const int& b)

inline int min(const int& a, const int& b)

inline int sub(const int& a, const int& b)

inline int read()

int n,m,lim=1,len,invn,a[n],b[n],r[n];

inline int qpow(int x, int y)

return res;

}inline void ntt(int* a, int tp)

} }}int main()

學習筆記 多項式

給你n個點 x 1,y 1 x 2,y 2 求乙個n 1次的多項式 f x 求 f k 我們可以認為 f x f 1 x f 2 x f x 其中 f i x i y i 且 forall j neq i,f i x j 0 也就是說乙個點 x i 只在乙個函式中為 y i 其他函式中均為0 換言之...

學習筆記 多項式

把一直學不懂的各種大常數 o n log n 的神奇多項式演算法總結一下 證明什麼的比較簡略 還有我今天才知道預處理一下單位根會快很多 qwq 最沒用的乙個 首先我們能寫出乙個 o n 2 的暴力 這個你都不會就可以退役了 某位dalao題解中的 要確定乙個多項式,我們發現只要代 f 1 f 2 f...

多項式學習筆記

太菜了並不是很理解多項式,簡單記錄一下,緩慢更新吧 有問題問快速航 首先我們要求的柿子長這樣 c k sum a i b j 大概思路 先把兩個多項式轉成點值 dft 再把兩個多項式的點值乘在一起,把新的點值轉成多項式 idft 即可 首先要了解複數的運算 a b i c d i a c b d i...