(首先要%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)\)
- 求解
從最簡單的情況開始考慮,當\(n=1\)的時候\(A(x)\equiv\ c\ (mod\ x)\),\(c\)為\(A(x)\)的常數項,此時\(A^{-1}(x)\)為\(c\)的逆元
在這個基礎上我們繼續考慮一般情況
對於\(n>1\)的情況,不妨設\(B(x)=A^{-1}(x)\),那么我們可以根據定義列出下面的式子:
這里的話考慮用倍增的方式求解(算倍增吧),這里假設我們已經知道了\(A(x)\)在\(mod\ x^{\lceil \frac{n}{2} \rceil}\)下的逆元\(G(x)\),那么有:
我們把\(A(x)\)和\(B(x)\)的式子寫成\(mod\ x^{\lceil \frac{n}{2} \rceil}\)下的:
(可以這么寫是因為\(mod\ x^n\)相當於將乘積中\(x\)次數大於等於\(n\)的忽略掉了,而\(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\)
那么我們就可以寫成:
兩邊同時乘上\(A(x)\),由逆元的定義我們可以將上面的式子化簡成下面這樣:
最后得到:
也就是說,如果我們知道\(G(x)\),我們就可以推出\(B(x)\)了
具體的實現可以用遞歸的方式實現,中間的多項式乘法可以用fft加速一下,那么最終的時間復雜度就是
然而為啥這樣搞完了還是一個log呢?因為每次遞歸下去多項式的最高次數都會減半,稍微算一下就會發現最后總的時間復雜度合起來還是一個log而不是兩個
注意,后面這一堆推式子的過程是建立在\(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)\),根據定義我們可以列出式子:
我們對這個式子進行一些處理:
那么可以得到(因為右邊是\(0\)所以可以這么搞):
然后兩邊加上\(4G^2(x)A(x)\):
我們將\((2G^2(x))^2\)移到左邊去,將左邊寫成一個平方的形式,得到:
等式左邊的東西就是我們要求的\(B(x)\)
所以如果說我們知道了\(G(x)\),我們也就可以得出\(B(x)\)啦,分母可以用多項式求逆搞一下,其他的多項式乘法fft搞一下,問題不大
總的復雜度是:
- 實現
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)\)就是余數,我們現在考慮求商
- 求解
為了方便接下來的表述,先定義一些操作,我們記:
也就是系數反轉,舉個簡單的例子:
那么現在我們把上面那條式子搬下來:
(接下來的步驟均將\(D(x)\)看成\(n-m\)次多項式,\(R(x)\)看成\(m-1\)次多項式,對於那些不存在的高次項我們就把系數看成\(0\)就好了)
后面的余數看起來十分不友善,所以我們要想個辦法把它去掉,於是我們可以進行以下的操作:
我們將上面式子中的所有\(x\)換成\(\frac{1}{x}\),然后等式兩邊同時乘上\(x^n\),得到:
現在再來看一下各個項的最高次項,首先是我們要求的元素\(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(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
