【学习笔记】多项式基础
1.1 1.1 1.1 多项式乘法逆元:满足 F ( x ) ∗ G ( x ) = 1 F(x)*G(x)=1 F(x)∗G(x)=1时,称 F ( x ) , G ( x ) F(x),G(x) F(x),G(x)互为乘法逆元。保证 f 0 ≠ 0 f_0\ne 0 f0=0。
考虑倍增算法。当界为 ( m o d x ) \pmod x (modx),即多项式只有常数项时,直接求数字逆元即可满足条件。
假设我们已经得到了 R ∗ ( x ) = F ( x ) − 1 ( m o d x n / 2 ) R_*(x)=F(x)^{-1}\pmod {x^{n/2}} R∗(x)=F(x)−1(modxn/2)
设 R ( x ) = F ( x ) − 1 ( m o d x n ) R(x)=F(x)^{-1}\pmod{x^n} R(x)=F(x)−1(modxn)
那么 R ( x ) = R ∗ ( x ) ( m o d x n / 2 ) R(x)=R_*(x)\pmod {x^{n/2}} R(x)=R∗(x)(modxn/2),作差得 R ( x ) − R ∗ ( x ) = 0 ( m o d x n / 2 ) R(x)-R_*(x)=0\pmod {x^{n/2}} R(x)−R∗(x)=0(modxn/2)
平方得 ( R ( x ) − R ∗ ( x ) ) 2 = 0 ( m o d x n ) (R(x)-R_*(x))^2=0\pmod {x^{n}} (R(x)−R∗(x))2=0(modxn)
展开得 R ( x ) 2 − 2 R ( x ) R ∗ ( x ) + R ∗ ( x ) 2 = 0 ( m o d x n ) R(x)^2-2R(x)R_*(x)+R_*(x)^2=0\pmod{x^n} R(x)2−2R(x)R∗(x)+R∗(x)2=0(modxn)
两边同乘 F ( x ) F(x) F(x),得到 R ( x ) − 2 R ∗ ( x ) + R ∗ ( x ) 2 F ( x ) = 0 ( m o d x n ) R(x)-2R_*(x)+R_*(x)^2F(x)=0\pmod{x^n} R(x)−2R∗(x)+R∗(x)2F(x)=0(modxn)
那么 R ( x ) = 2 R ∗ ( x ) − R ∗ ( x ) 2 F ( x ) ( m o d x n ) R(x)=2R_*(x)-R_*(x)^2F(x)\pmod{x^n} R(x)=2R∗(x)−R∗(x)2F(x)(modxn)
根据这个即可从 R ∗ ( x ) R_*(x) R∗(x)求得 R ( x ) R(x) R(x),实现次数倍增。
复杂度 O ( n log n ) O(n\log n) O(nlogn)。
1.2 1.2 1.2 泰勒级数和麦克劳林级数:
泰勒级数用无限项连加式来表示函数。一般的,对于一个光滑函数 f ( x ) f(x) f(x),有
f ( x ) = ∑ n = 0 f ( n ) ( a ) n ! ( x − a ) n f(x)=\sum_{n=0}\frac{f^{(n)}(a)}{n!}(x-a)^n f(x)=n=0∑n!f(n)(a)(x−a)n
这个式子被称为 f ( x ) f(x) f(x)在 a a a处的泰勒展开式;在 0 0 0处的展开式也被称为麦克劳林展开式或麦克劳林级数。
1.3 1.3 1.3 一般的 Newton’s Method:
一般用于求解非线性方程 f ( x ) = 0 f(x)=0 f(x)=0的根。算法如下:
- 选取一个合适的数作为 x 0 x_0 x0
- 将 f ( x ) f(x) f(x)在 x 0 x_0 x0处展开,即 f ( x ) = ∑ n = 0 f ( n ) ( x 0 ) n ! ( x − x 0 ) n f(x)=\sum_{n=0}\frac{f^{(n)}(x_0)}{n!}(x-x_0)^n f(x)=∑n=0n!f(n)(x0)(x−x0)n
- 取其常数项和线性项的系数,令其等于 0 0 0,即 f ( x 0 ) + f ′ ( x 0 ) ( x − x 0 ) = 0 f(x_0)+f'(x_0)(x-x_0)=0 f(x0)+f′(x0)(x−x0)=0
- 解得这个近似线性方程的根 x 1 x_1 x1,可以证明证明每个新解都更接近 f ( x ) = 0 f(x)=0 f(x)=0的根
1.4 1.4 1.4 Newton’s Method 在多项式中的 Methodology:
定义多项式的求导:
F ′ ( x ) = ∑ i = 1 n F [ i ] i x i − 1 F'(x)=\sum_{i=1}^nF[i]ix^{i-1} F′(x)=i=1∑nF[i]ixi−1
定义多项式的积分:
∫ F ( x ) = C + ∑ i = 0 n F [ i ] x i + 1 / ( i + 1 ) \int F(x)=C+\sum_{i=0}^nF[i]x^{i+1}/(i+1) ∫F(x)=C+i=0∑nF[i]xi+1/(i+1)
定义多项式复合为:
F ( G ( x ) ) = ∑ i = 0 n F [ i ] G ( x ) i F(G(x))=\sum_{i=0}^nF[i]G(x)^i F(G(x))=i=0∑nF[i]G(x)i
已知函数 g g g且 g ( f ( x ) ) = 0 g(f(x))=0 g(f(x))=0,求 f ( x ) ( m o d x n ) f(x)\pmod{x^n} f(x)(modxn)
选择一个满足 g ( f ( x ) ) = 0 ( m o d x ) g(f(x))=0\pmod x g(f(x))=0(modx)的多项式作为初始根。
设我们已经求出了模 x n / 2 x^{n/2} xn/2意义下的根 f 0 ( x ) f_0(x) f0(x),将 g ( f ( x ) ) g(f(x)) g(f(x))在 f 0 ( x ) f_0(x) f0(x)处展开:
g ( f ( x ) ) = ∑ i = 0 g ( i ) ( f 0 ( x ) ) i ! ( f ( x ) − f 0 ( x ) ) i g(f(x))=\sum_{i=0}\frac{g^{(i)}(f_0(x))}{i!}(f(x)-f_0(x))^i g(f(x))=i=0∑i!g(i)(f0(x))(f(x)−f0(x))i
将 f ( x ) = f 0 ( x ) + x n / 2 ∗ h ( x ) f(x)=f_0(x)+x^{n/2}*h(x) f(x)=f0(x)+xn/2∗h(x)带入,即
g ( f ( x ) ) = ∑ i = 0 g ( i ) ( f 0 ( x ) ) i ! x n / 2 ∗ i h i ( x ) g(f(x))=\sum_{i=0}\frac{g^{(i)}(f_0(x))}{i!}x^{n/2*i}h^i(x) g(f(x))=i=0∑i!g(i)(f0(x))xn/2∗ihi(x)
当 x ≥ 2 x\ge 2 x≥2时有 x n / 2 ∗ i h i ( x ) = 0 ( m o d x n ) x^{n/2*i}h^i(x)=0\pmod{x^n} xn/2∗ihi(x)=0(modxn),则在模 x n x^n xn意义下的泰勒级数,从第 3 3 3项开始全部为 0 0 0,于是只需保留前两项:
g ( f 0 ( x ) ) + g ′ ( f 0 ( x ) ) ∗ x n / 2 ∗ h ( x ) = 0 g(f_0(x))+g'(f_0(x))*x^{n/2}*h(x)=0 g(f0(x))+g′(f0(x))∗xn/2∗h(x)=0
解得
h ( x ) = − x − n / 2 g ( f 0 ( x ) ) g ′ ( f 0 ( x ) ) ( m o d x n ) h(x)=-x^{-n/2}\frac{g(f_0(x))}{g'(f_0(x))}\pmod{x^n} h(x)=−x−n/2g′(f0(x))g(f0(x))(modxn)
在 h ( x ) h(x) h(x)存在的情况下回代得
f ( x ) = f 0 ( x ) − g ( f 0 ( x ) ) g ′ ( f 0 ( x ) ) ( m o d x n ) f(x)=f_0(x)-\frac{g(f_0(x))}{g'(f_0(x))}\pmod{x^n} f(x)=f0(x)−g′(f0(x))g(f0(x))(modxn)
经验告诉我们 h ( x ) h(x) h(x)总是存在。由上述过程可知, g ( f ( x ) ) = 0 ( m o d x n ) g(f(x))=0\pmod{x^n} g(f(x))=0(modxn) 的根存在,当且仅当这个同余方程在模 x 1 x^1 x1的意义下的根 f 0 f_0 f0存在,并且每个 f 0 f_0 f0都对应一个唯一的模 x n x^n xn的根。
1.5 1.5 1.5 多项式开根:
得 B ( x ) 2 − A ( x ) = 0 B(x)^2-A(x)=0 B(x)2−A(x)=0,此处 A ( x ) A(x) A(x)已知。保证 a 0 = 1 a_0=1 a0=1。
令 G ( B ( x ) ) = B ( x ) 2 − A ( x ) G(B(x))=B(x)^2-A(x) G(B(x))=B(x)2−A(x)
则 G ′ ( B ( x ) ) = 2 B ( x ) G'(B(x))=2B(x) G′(B(x))=2B(x)
根据牛顿迭代得到: B ( x ) = B ∗ ( x ) − G ( B ∗ ( x ) ) G ′ ( B ∗ ( x ) ) = B ∗ ( x ) − B ∗ ( x ) 2 − A ( x ) 2 B ∗ ( x ) = A ( x ) + B ∗ ( x ) 2 2 B ∗ ( x ) B(x)=B_*(x)-\frac{G(B_*(x))}{G'(B_*(x))} \\=B_*(x)-\frac{B_*(x)^2-A(x)}{2B_*(x)}=\frac{A(x)+B_*(x)^2}{2B_*(x)} B(x)=B∗(x)−G′(B∗(x))G(B∗(x))=B∗(x)−2B∗(x)B∗(x)2−A(x)=2B∗(x)A(x)+B∗(x)2
根据这个倍增即可。复杂度 O ( n log n ) O(n\log n) O(nlogn)。
1.6 1.6 1.6 多项式带余除法:
我们定义 n n n次多项式的反转操作 F T ( x ) = x n F ( x − 1 ) F^T(x)=x^nF(x^{-1}) FT(x)=xnF(x−1)
那么 F ( x ) = Q ( x ) G ( x ) + R ( x ) F(x)=Q(x)G(x)+R(x) F(x)=Q(x)G(x)+R(x),其中 F ( x ) F(x) F(x)和 G ( x ) G(x) G(x)已知
换元得到 F ( x − 1 ) = Q ( x − 1 ) G ( x − 1 ) + R ( x − 1 ) F(x^{-1})=Q(x^{-1})G(x^{-1})+R(x^{-1}) F(x−1)=Q(x−1)G(x−1)+R(x−1)
两边同乘 x n x^n xn: x n F ( x − 1 ) = x n Q ( x − 1 ) G ( x − 1 ) + x n R ( x − 1 ) x^nF(x^{-1})=x^nQ(x^{-1})G(x^{-1})+x^nR(x^{-1}) xnF(x−1)=xnQ(x−1)G(x−1)+xnR(x−1)
写成反转的形式, F T ( x ) = Q T ( x ) G T ( x ) + x n − m + 1 R T ( x ) F^T(x)=Q^T(x)G^T(x)+x^{n-m+1}R^T(x) FT(x)=QT(x)GT(x)+xn−m+1RT(x)
两边同时模 x n − m + 1 x^{n-m+1} xn−m+1,得到 F T ( x ) = Q T ( x ) G T ( x ) ( m o d x n − m + 1 ) F^T(x)=Q^T(x)G^T(x)\pmod{x^{n-m+1}} FT(x)=QT(x)GT(x)(modxn−m+1)
变形得 Q T ( x ) = F T ( x ) G T ( x ) − 1 ( m o d x n − m + 1 ) Q^T(x)=F^T(x)G^T(x)^{-1}\pmod{x^{n-m+1}} QT(x)=FT(x)GT(x)−1(modxn−m+1)
求出 Q T ( x ) Q^T(x) QT(x)后翻转即可得到 Q ( x ) Q(x) Q(x)。
R ( x ) = F ( x ) − Q ( x ) G ( x ) R(x)=F(x)-Q(x)G(x) R(x)=F(x)−Q(x)G(x),容易算出余数。
复杂度 O ( n log n ) O(n\log n) O(nlogn)。
1.7 1.7 1.7 多项式 ln , exp \ln,\exp ln,exp
两者均由麦克劳林级数定义:
ln ( F ( x ) ) = − ∑ i = 1 ( 1 − F ( x ) ) i i exp ( F ( x ) ) = ∑ i = 0 F ( x ) i i ! \ln(F(x))=-\sum_{i=1}\frac{(1-F(x))^i}{i}\\\exp(F(x))=\sum_{i=0}\frac{F(x)^i}{i!} ln(F(x))=−i=1∑i(1−F(x))iexp(F(x))=i=0∑i!F(x)i
在这个定义下, ln \ln ln和 exp \exp exp仍为互逆运算。
1.7.1 1.7.1 1.7.1 给定 n n n次多项式 A ( x ) A(x) A(x),求 ln ( A ( x ) ) ( m o d x n ) \ln(A(x))\pmod{x^n} ln(A(x))(modxn),保证 a 0 = 1 a_0=1 a0=1
相当于 B ( x ) = ln ( A ( x ) ) ( m o d x n ) B(x)=\ln(A(x))\pmod{x^n} B(x)=ln(A(x))(modxn)
两边同时求导(对 x x x求导), B ′ ( x ) = A ( x ) ′ A ( x ) ( m o d x n ) B'(x)=\frac{A(x)'}{A(x)}\pmod{x^n} B′(x)=A(x)A(x)′(modxn)
两边同时积分, B ( x ) = ∫ A ( x ) ′ A ( x ) ( m o d x n ) B(x)=\int \frac{A(x)'}{A(x)}\pmod{x^n} B(x)=∫A(x)A(x)′(modxn)
需要一次多项式求导,一次多项式求逆,一次多项式积分。复杂度 O ( n log n ) O(n\log n) O(nlogn)。
1.7.2 1.7.2 1.7.2 给定 n n n次多项式 A ( x ) A(x) A(x),求 exp ( A ( x ) ) ( m o d x n ) \exp(A(x))\pmod{x^n} exp(A(x))(modxn),保证 a 0 = 0 a_0=0 a0=0
相当于 B ( x ) = exp ( A ( x ) ) ( m o d x n ) B(x)=\exp(A(x))\pmod{x^n} B(x)=exp(A(x))(modxn)
即 A ( x ) − ln ( B ( x ) ) = 0 A(x)-\ln(B(x))=0 A(x)−ln(B(x))=0,定义 g ( f ( x ) ) = A ( x ) − ln ( f ( x ) ) g(f(x))=A(x)-\ln(f(x)) g(f(x))=A(x)−ln(f(x)),带入 Newton’s Method 得
f ( x ) = f 0 ( x ) − g ( f 0 ( x ) ) g ′ ( f 0 ( x ) ) = f 0 ( x ) − ( ln f 0 ( x ) − A ( x ) ) ∗ f 0 ( x ) = f 0 ( x ) ( 1 − ln f 0 ( x ) + A ( x ) ) f(x)=f_0(x)-\frac{g(f_0(x))}{g'(f_0(x))}=f_0(x)-(\ln f_0(x)-A(x))*f_0(x)\\=f_0(x)(1-\ln f_0(x)+A(x)) f(x)=f0(x)−g′(f0(x))g(f0(x))=f0(x)−(lnf0(x)−A(x))∗f0(x)=f0(x)(1−lnf0(x)+A(x))
倍增算即可。复杂度 O ( n log n ) O(n\log n) O(nlogn)。
1.8
1.8
1.8 多项式快速幂
给定
n
n
n次多项式
A
(
x
)
A(x)
A(x),求
A
(
x
)
k
(
m
o
d
x
n
)
A(x)^k\pmod{x^n}
A(x)k(modxn),保证
a
0
=
1
a_0=1
a0=1
公式非常简单: A ( x ) k = exp ( k ln A ( x ) ) A(x)^k=\exp(k\ln A(x)) A(x)k=exp(klnA(x))
复杂度 O ( n log n ) O(n\log n) O(nlogn)。
1.9
1.9
1.9 任意多项式快速幂
给定
n
n
n次多项式
A
(
x
)
A(x)
A(x),求
A
(
x
)
k
(
m
o
d
x
n
)
A(x)^k\pmod{x^n}
A(x)k(modxn),不保证
a
0
=
1
a_0=1
a0=1
记 A ( x ) = c x m B ( x ) A(x)=cx^mB(x) A(x)=cxmB(x),其中 b 0 = 1 b_0=1 b0=1
那么 A ( x ) k = c k x m k B ( x ) k A(x)^k=c^kx^{mk}B(x)^k A(x)k=ckxmkB(x)k,可以计算。
复杂度 O ( n log n ) O(n\log n) O(nlogn)。
#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define db long double
#define cpx complex<db>
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N=4e5+5;
const int mod=998244353;
int n;
ll fac[N],inv[N],inv2=(mod+1)/2;
ll fpow(ll x,ll y=mod-2){
ll z(1);
for(;y;y>>=1){
if(y&1)z=z*x%mod;
x=x*x%mod;
}return z;
}
void init(int n){
fac[0]=1;for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
inv[n]=fpow(fac[n]);for(int i=n;i>=1;i--)inv[i-1]=inv[i]*i%mod;
}
ll omega(int n,int k,int I){
if(!I)return fpow(3,(mod-1)/n*k);
return fpow(3,(mod-1)/n*(n-k));
}
void ntt(ll *a,int n,int I=0){
int k=0;while((1<<k)<n)k++;
for(int i=0;i<n;i++){
int t=0;
for(int j=0;j<k;j++)if(i&(1<<j))t|=(1<<(k-j-1));
if(i<t)swap(a[i],a[t]);
}
for(int l=2;l<=n;l<<=1){
int m=l/2;ll y=omega(l,1,I);
for(ll *p=a;p!=a+n;p+=l){
ll x=1;
for(int i=0;i<m;i++){
ll z=x*p[i+m]%mod;
p[m+i]=(p[i]-z)%mod;
p[i]=(p[i]+z)%mod;
x=x*y%mod;
}
}
}if(I){
ll l=fpow(n);for(int i=0;i<1<<k;i++)a[i]=a[i]*l%mod;
}
}
struct poly{
ll a[N];
poly(){memset(a,0,sizeof a);}
friend poly operator *(poly a,poly b){
int k=0;while((1<<k)<(n<<1))k++;
for(int i=n;i<1<<k;i++)a.a[i]=b.a[i]=0;
ntt(a.a,1<<k),ntt(b.a,1<<k);
for(int i=0;i<1<<k;i++)a.a[i]=a.a[i]*b.a[i]%mod;
ntt(a.a,1<<k,1);
for(int i=n;i<1<<k;i++)a.a[i]=0;
return a;
}
friend poly operator +(poly a,poly b){
for(int i=0;i<n;i++)a.a[i]=(a.a[i]+b.a[i])%mod;
return a;
}
friend poly operator -(poly a,poly b){
for(int i=0;i<n;i++)a.a[i]=(a.a[i]+mod-b.a[i])%mod;
return a;
}
friend poly operator *(poly a,ll b){
for(int i=0;i<n;i++)a.a[i]=a.a[i]*b%mod;
return a;
}
}f;
poly Inv(poly a){
poly b,aa=a;b.a[0]=fpow(a.a[0]);int n2=n;
int l;
for(l=1;l<n2;l<<=1){
n=l<<1;
for(int i=0;i<n;i++)a.a[i]=aa.a[i];for(int i=n;i<n<<1;i++)a.a[i]=0;
ntt(b.a,n<<1),ntt(a.a,n<<1);
for(int i=0;i<n<<1;i++)b.a[i]=(2*b.a[i]-b.a[i]*b.a[i]%mod*a.a[i]%mod)%mod;
ntt(b.a,n<<1,1);for(int i=n;i<n<<1;i++)b.a[i]=0;
}n=n2;for(int i=n;i<l;i++)b.a[i]=0;
return b;
}
poly sqrt(poly a){
poly b,bb,aa=a;b.a[0]=1;int n2=n;
int l;
for(l=1;l<n2;l<<=1){
n=l<<1;bb=Inv(b);
for(int i=0;i<n;i++)a.a[i]=aa.a[i];for(int i=n;i<n<<1;i++)a.a[i]=0;
ntt(a.a,n<<1),ntt(b.a,n<<1),ntt(bb.a,n<<1);
for(int i=0;i<n<<1;i++)b.a[i]=(b.a[i]+a.a[i]*bb.a[i]%mod)%mod*inv2%mod;
ntt(b.a,n<<1,1);for(int i=n;i<n<<1;i++)b.a[i]=0;
}n=n2;for(int i=n;i<l;i++)b.a[i]=0;
return b;
}
poly der(poly a){
for(int i=1;i<n;i++)a.a[i-1]=a.a[i]*i%mod;
a.a[n-1]=0;return a;
}
poly Int(poly a){
for(int i=n-2;i>=0;i--)a.a[i+1]=a.a[i]*fpow(i+1)%mod;
a.a[0]=0;return a;
}
poly ln(poly a){
return Int(der(a)*Inv(a));
}
poly exp(poly a){
poly b,bb;b.a[0]=1;int n2=n;
int l;
for(l=1;l<n2;l<<=1){
n=l<<1;bb=ln(b);
for(int i=0;i<n;i++)bb.a[i]=(a.a[i]-bb.a[i])%mod;for(int i=n;i<n<<1;i++)bb.a[i]=0;
bb.a[0]++;
ntt(b.a,n<<1),ntt(bb.a,n<<1);
for(int i=0;i<n<<1;i++)b.a[i]=b.a[i]*bb.a[i]%mod;
ntt(b.a,n<<1,1);for(int i=n;i<n<<1;i++)b.a[i]=0;
}n=n2;for(int i=n;i<l;i++)b.a[i]=0;
return b;
}
poly power(poly a,ll K){
return exp(ln(a)*K);
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
}

浙公网安备 33010602011771号