(首先要%miskcoo,這位dalao寫的博客實在是太強啦qwq大部分多項式相關的知識都是從這位dalao博客裏面學的,做爲一隻蒟蒻仍是瘋狂膜拜後本身理下思路吧qwq)函數
對於一個多項式\(A(x)\),若是存在一個多項式\(B(x)\),知足\(B(x)\)的次數小於等於\(A(x)\)且\(A(x)B(x)\equiv 1(mod\ x^n)\),那麼咱們稱\(B(x)\)爲\(A(x)\)在模\(x^n\)意義下的逆元,簡單記做\(A^{-1}(x)\)ui
從最簡單的狀況開始考慮,當\(n=1\)的時候\(A(x)\equiv\ c\ (mod\ x)\),\(c\)爲\(A(x)\)的常數項,此時\(A^{-1}(x)\)爲\(c\)的逆元spa
在這個基礎上咱們繼續考慮通常狀況code
對於\(n>1\)的狀況,不妨設\(B(x)=A^{-1}(x)\),那麼咱們能夠根據定義列出下面的式子:
\[ A(x)B(x)\equiv 1(mod\ x^n) \]
這裏的話考慮用倍增的方式求解(算倍增吧),這裏假設咱們已經知道了\(A(x)\)在\(mod\ x^{\lceil \frac{n}{2} \rceil}\)下的逆元\(G(x)\),那麼有:
\[ A(x)G(x)\equiv 1(mod\ x^{\lceil \frac{n}{2} \rceil}) \]
咱們把\(A(x)\)和\(B(x)\)的式子寫成\(mod\ x^{\lceil \frac{n}{2} \rceil}\)下的:blog
(能夠這麼寫是由於\(mod\ x^n\)至關於將乘積中\(x\)次數大於等於\(n\)的忽略掉了,而\(mod\ x^{\lceil \frac{n}{2} \rceil}\)則至關於忽略了更多的項,既然前者知足,那麼後者確定也知足)遞歸
\[ A(x)B(x)\equiv 1 (mod\ x^{\lceil \frac{n}{2} \rceil}) \]get
把這兩條式子相減,就能夠搞事情了:
\[ \begin{aligned} A(x)[B(x)-G(x)]&\equiv 0\ (mod\ x^{\lceil \frac{n}{2} \rceil})\\ B(x)-G(x)&\equiv 0\ (mod\ x^{\lceil \frac{n}{2} \rceil})\\ \end{aligned} \]
而後咱們兩邊平方一下:
\[ B^2(x)-2B(x)G(x)+G^2(x)\equiv 0\ (mod\ x^{\lceil \frac{n}{2} \rceil}) \]
而後這裏有個很神奇的事情,\(B(x)-G(x)\) 在\(mod\ x^{\lceil \frac{n}{2} \rceil}\)下爲0,說明這個式子最後的結果的\(0\)到\(\lceil \frac{n}{2} \rceil -1\)次項係數都爲\(0\),平方了以後,對於結果的\(i\)次項係數,(\(0<=i<=2*\lceil \frac{n}{2} \rceil -1\) ),其係數\(a_i = \sum\limits_{j=0}^{i}a_j a_{i-j}\),而\(a_j\)和\(a_{i-j}\)中一定有一項爲\(0\)(由於\(j\)和\(i-j\)中一定有一個值小於\(\lceil \frac{n}{2} \rceil\)),因此咱們能夠獲得一個結論,這個式子在平方了以後在\(mod \ x^n\)下也是\(0\)博客
那麼咱們就能夠寫成:
\[ \begin{aligned} B^2(x)-2B(x)G(x)+G^2(x)&\equiv 0\ (mod\ x^n)\\ A(x)B(x)*B(x)-2*A(x)B(x)*G(x)+A(x)G^2(x)&\equiv 0\ (mod\ x^n)\\ \end{aligned} \]
兩邊同時乘上\(A(x)\),由逆元的定義咱們能夠將上面的式子化簡成下面這樣:
\[ B(x)-2G(x)+A(x)G^2(x)\equiv 0\ (mod\ x^n) \]
最後獲得:
\[ B(x)\equiv 2G(x)-A(x)G^2(x)\ (mod\ x^n) \]
也就是說,若是咱們知道\(G(x)\),咱們就能夠推出\(B(x)\)了it
具體的實現能夠用遞歸的方式實現,中間的多項式乘法能夠用fft加速一下,那麼最終的時間複雜度就是
\[ T(n)=T(\frac{n}{2})+O(n \ log\ n)=O(n\ log \ n) \]
然而爲啥這樣搞完了仍是一個log呢?由於每次遞歸下去多項式的最高次數都會減半,稍微算一下就會發現最後總的時間複雜度合起來仍是一個log而不是兩個io
注意,後面這一堆推式子的過程是創建在\(n=1\)的時候有解的前提下的,因此咱們還能夠獲得一個結論:一個多項式在\(mod\ x^n\)下是否有逆元取決於其常數項在\(mod \ x^n\)下是否有逆元
首先先實現一個namespace NTT,而後除了基礎的函數外主要供外部調用的過程是這個:
void Ntt_getinv(vct &a,vct &b,int n,int m){ prework(a,b,n,2*m);//這裏注意由於後面是A*B*B,因此m要*2 ntt(A,1); ntt(B,1); for (int i=0;i<len;++i) B[i]=(2LL-1LL*A[i]*B[i]%MOD+MOD)*1LL*B[i]%MOD; ntt(B,-1); }
而後求逆的過程大概是這樣(這裏用vector來寫了):
vct Inv(vct a){ int N=a.size(); if (N==1){ a[0]=ksm(a[0],MOD-2); return a; } vct b=a; b.resize((N+1)>>1); b=Inv(b); b.resize(N); NTT::Ntt_getinv(a,b,N,N); b.resize(NTT::len); for (int i=0;i<NTT::len;++i) b[i]=NTT::B[i]; b.resize(N); return b; }
求逆大概就是這樣吧ovo
對於一個多項式\(A(x)\),若是存在一個多項式\(B(x)\),知足\(B^2(x)\equiv\ A(x) (mod\ x^n)\),則稱\(B(x)\)爲\(A(x)\)在\(mod\ x^n\)下的平方根
一樣是考慮最簡單的狀況,當\(n=0\)的時候,\(B(x)\)的常數項就是\(1\)
而後考慮通常狀況,一樣的思路,考慮用倍增的方式來求
假設咱們已經知道了\(A(x)\)在\(mod\ x^{n}\)下的平方根\(G(x)\),如今要求在\(mod\ x^{2n}\)下的平方根\(B(x)\),根據定義咱們能夠列出式子:
\[ \begin{aligned} B^2(x)&\equiv A(x)(mod\ x^{2n})\\ G^2(x)&\equiv A(x)(mod\ x^n) \end{aligned} \]
咱們對這個式子進行一些處理:
\[ \begin{aligned} G^2(x)&\equiv A(x)(mod\ x^n)\\ G^2(x)-A(x)&\equiv 0(mod\ x^n)\\ \end{aligned} \]
那麼能夠獲得(由於右邊是\(0\)因此能夠這麼搞):
\[ \begin{aligned} (G^2(x)-A(x))^2&\equiv 0 (mod\ x^{2n})\\ G^4(x)-2G^2(x)A(x)+A^2(x)&\equiv 0(mod\ x^{2n})\\ \end{aligned} \]
而後兩邊加上\(4G^2(x)A(x)\):
\[ \begin{aligned} G^4(x)+2G^2(x)A(x)+A^2(x)&\equiv 4G^2(x)A(x)(mod\ x^{2n})\\ (G^2(x)+A(x))^2&\equiv 4G^2(x)A(x)(mod\ x^{2n})\\ (G^2(x)+A(x))^2&\equiv (2G(x))^2A(x)(mod\ x^{2n})\\ \end{aligned} \]
咱們將\((2G^2(x))^2\)移到左邊去,將左邊寫成一個平方的形式,獲得:
\[ (\frac{G^2(x)+A(x)}{2G(x)})^2\equiv A(x)(mod\ x^{2n}) \]
等式左邊的東西就是咱們要求的\(B(x)\)
因此若是說咱們知道了\(G(x)\),咱們也就能夠得出\(B(x)\)啦,分母能夠用多項式求逆搞一下,其餘的多項式乘法fft搞一下,問題不大
總的複雜度是:
\[ T(n)=T(\frac{n}{2})+求逆複雜度+O(n\ log \ n)=O(n\ log\ n) \]
namespace NTT中主要須要調用的過程長這個樣子
void Ntt_getsqrt(vct &a,vct &invb,int n,int m){ prework(a,invb,n,m); ntt(A,1); ntt(B,1); for (int i=0;i<len;++i) B[i]=1LL*B[i]*inv2%MOD*A[i]%MOD; ntt(B,-1); }
開根的話大概長這個樣子
vct Sqrt(vct a){ int N=a.size(),M,M1; if (N==1){ a[0]=1; return a; } vct b=a,invb; b.resize((N+1)>>1); b=Sqrt(b); invb=b; invb.resize(N);//resize!!! invb=Inv(invb); NTT::Ntt_getsqrt(a,invb,N,N); b.resize(NTT::len); for (int i=0;i<NTT::len;++i) b[i]=(1LL*b[i]*inv2%MOD+NTT::B[i])%MOD; b.resize(N); return b; }
給出一個\(n\)次多項式\(A(x)\),以及一個\((m(m<=n)\)次多項式\(B(x)\)
要求出\(D(x)\)知足\(A(x)=D(x)B(x)+R(x)\),且\(D(x)\)的次數\(<=n-m\),\(R(x)\)的次數\(<m\)
簡單來講就是類比整數的除法,\(D(x)\)就是商,\(R(x)\)就是餘數,咱們如今考慮求商
爲了方便接下來的表述,先定義一些操做,咱們記:
\[ rev(A(x))=x^nA(\frac{1}{n}) \]
也就是係數反轉,舉個簡單的例子:
\[ \begin{aligned} A(x)&=4x^4+3x^3+2x^2+1\\ rev(A(x))&=x^4+2x^3+3x^2+4 \end{aligned} \]
那麼如今咱們把上面那條式子搬下來:
\[ A(x)=D(x)B(x)+R(x) \]
(接下來的步驟均將\(D(x)\)當作\(n-m\)次多項式,\(R(x)\)當作\(m-1\)次多項式,對於那些不存在的高次項咱們就把係數當作\(0\)就行了)
後面的餘數看起來十分不友善,因此咱們要想個辦法把它去掉,因而咱們能夠進行如下的操做:
咱們將上面式子中的全部\(x\)換成\(\frac{1}{x}\),而後等式兩邊同時乘上\(x^n\),獲得:
\[ \begin{aligned} x^nA(\frac{1}{x})&=x^{n-m}D(\frac{1}{x})x^mB(\frac{1}{x})+x^{n-m+1}x^{m-1}R(\frac{1}{x})\\ rev(A(x))&=rev(D(x))rev(B(x))+x^{n-m+1}rev(R(x))\\ \end{aligned} \]
如今再來看一下各個項的最高次項,首先是咱們要求的元素\(D(x)\),因爲這個多項式原來是\(n-m\)次,因此在係數反轉以後確定不會超過\(n-m\)次,而咱們要「消掉」的\(R(x)\)原來是\(m-1\)次多項式,因此\(x^{n-m+1}R(x)\)的最低次項應該是大於\(n-m\) 的
那麼考慮將上面的式子放到\(mod\ x^{n-m+1}\)下,\(x^{n-m+1}R(x)\)的影響就能夠十分愉快滴被消掉啦,同時咱們也不會影響到\(D(x)\)的求解,由於\(D(x)\)是\(n-m\)次的(瘋狂%miskcoo太強了qwq)
因而咱們就獲得了這樣一個式子:
\[ rev(A(x))\equiv\ rev(D(x))rev(B(x))\ (mod\ x^{n-m+1}) \]
那因此,咱們只要求一個\(rev(B(x))\)在\(mod x^{n-m+1}\)意義下的逆元而後跟\(rev(A(x))\)乘一下,獲得\(rev(D(x))\),而後再把係數反轉回來就獲得\(D(x)\)啦
除法大概是長這個樣子
vct operator / (vct a,vct b){ int N=a.size()-1,M=b.size()-1; if (N<M){ d.resize(1);d[0]=0; return d; } reverse(a.begin(),a.end()); reverse(b.begin(),b.end()); b.resize(N-M+1); d=Inv_p(b)*a; d.resize(N-M+1); reverse(d.begin(),d.end()); return d; }
這個。。其實就是求上面那個\(R(x)\)
有了多項式除法(也就是求商)以後,求餘數就變得比較簡單了
類比整數的取模,咱們能夠獲得這樣的一個式子:
\[ R(x)=A(x)-D(x)B(x) \]
那就除法求出\(D(x)\)以後直接減一下就行了,\(D(x)B(x)\)這個多項式乘法也是直接用\(fft\)求就行了
僞裝很是短的樣子 (然而前面的東西都是要寫的qwq醒醒)
void mod(vct &a,vct b){ int N=a.size()-1,M=b.size()-1; if (N<M) return; t=a/b; a=a-(t*b); a.resize(M); }
大概。。就先寫這麼多吧ovo