【学习笔记】多项式基础

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)22R(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=0n!f(n)(a)(xa)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)(xx0)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)(xx0)=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=1nF[i]ixi1

定义多项式的积分:

∫ 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=0nF[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=0nF[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=0i!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/2h(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=0i!g(i)(f0(x))xn/2ihi(x)

x ≥ 2 x\ge 2 x2时有 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/2ihi(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/2h(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)=xn/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)2A(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)2A(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)2A(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(x1)

那么 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(x1)=Q(x1)G(x1)+R(x1)

两边同乘 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(x1)=xnQ(x1)G(x1)+xnR(x1)

写成反转的形式 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)+xnm+1RT(x)

两边同时模 x n − m + 1 x^{n-m+1} xnm+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)(modxnm+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(modxnm+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=1i(1F(x))iexp(F(x))=i=0i!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)(1lnf0(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); }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530057.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(72)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示