文章目录
基本概念
定义形如这样的函数为多项式:
f ( x ) = ∑ i = 0 n − 1 a i x i f(x)=\sum _{i=0} ^{n-1} a_ix^i f(x)=∑i=0n−1aixi
其中 n n n为多项式的项数(系数为0的项也是项), n − 1 n-1 n−1为多项式的最高次幂, a i a_i ai为多项式中 i i i次项的系数。
符号约定&说明
- 一般情况下,函数自变量均用 x x x表示。
- f ( x ) f(x) f(x)表示 f f f这个多项式
- f ( a ) f(a) f(a)表示自变量 x = a ( a 为 给 定 的 数 ) x=a(a为给定的数) x=a(a为给定的数)时 f f f的函数值
- f [ n ] f[n] f[n]表示多项式 f f f中 x n x^n xn一项的系数
- d e g ( f ) deg(f) deg(f)表示多项式 f f f的项数,也即最高次幂 − 1 -1 −1
- 求积分时,常数项默认为 0 0 0
求导&积分
求导:
对于某一项 x n x^n xn,求导为 n x n − 1 nx^{n-1} nxn−1。
设 h ( x ) = f ′ ( x ) h(x)=f'(x) h(x)=f′(x),则 h [ n ] = ( n + 1 ) f [ n + 1 ] ( 0 ≤ n < d e g ( h ) ) h[n]=(n+1)f[n+1](0\leq n<deg(h)) h[n]=(n+1)f[n+1](0≤n<deg(h)))
inline void getderivative(int n,int *f,int *h)
{
for(int i=0;i<n;++i) h[i]=mul(f[i+1],i+1);
h[n]=0;
}
积分:
设 h ( x ) = ∫ f ( x ) d x h(x)=\int f(x)dx h(x)=∫f(x)dx,则 h [ n ] = f [ n − 1 ] n ( 0 < n < d e g ( h ) , h [ 0 ] = 0 ) h[n]=\frac {f[n-1]}{n}(0<n<deg(h),h[0]=0) h[n]=nf[n−1](0<n<deg(h),h[0]=0)
inline void getintegration(int n,int *f,int *h)
{
for(int i=1;i<n;++i) h[i]=mul(f[i-1],inv[i]);//inv[i] i的逆元
h[0]=0;
}
点值表示&拉格朗日插值
多项式 f ( x ) f(x) f(x)不仅可以用每一项系数表示,由拉格朗日插值法,得到也可以用 d e g ( f ) deg(f) deg(f)个二元组 ( x i , f ( x i ) ) ( x i ≠ x j , i ≠ j ) (x_i,f(x_i))(x_i\neq x_j,i\neq j) (xi,f(xi))(xi̸=xj,i̸=j)来表示,也就是用 n n n个点来描述一个 n n n项多项式(即为点值表达式):
f ( x ) ∈ { d e g ( f ) < n 且 ∀ 0 ≤ i < n , f ( x i ) = y i , x i ≠ x j , i ≠ j } f(x)\in \{ deg(f)<n 且 \forall 0\leq i< n,f(x_i)=y_i,x_i\neq x_j,i\neq j\} f(x)∈{ deg(f)<n且∀0≤i<n,f(xi)=yi,xi̸=xj,i̸=j}
这种用点描述多项式的形式称为多项式的点值表示,由点值转化为系数式的过程称为插值。
卷积(Karatsuba算法&FTT&NTT)
多项式之间的乘积称为卷积。
设 h ( x ) = f ( x ) ∗ g ( x ) ( ∗ 即 为 卷 积 符 号 ) h(x)=f(x)*g(x)(*即为卷积符号) h(x)=f(x)∗g(x)(∗即为卷积符号),则 h [ n ] = ∑ i = 0 n f [ i ] g [ n − i ] ( 0 ≤ n < d e g ( h ) ) h[n]=\sum _{i=0}^{n} f[i]g[n-i](0\leq n<deg(h)) h[n]=∑i=0nf[i]g[n−i](0≤n<deg(h))。
设 d e g ( h ) = N deg(h)=N deg(h)=N。直接求多项式卷积,复杂度是 N 2 N^2 N2的,使用分治的 K a r a t s u b a Karatsuba Karatsuba算法可复杂度为 O ( n l o g 2 3 ) = O ( n 1.585 ) O(n^{log_2 3})=O(n^{1.585}) O(nlog23)=O(n1.585),使用 F F T / N T T FFT/NTT FFT/NTT可以将复杂度降到 N l o g N NlogN NlogN。
K a r a t s u b a Karatsuba Karatsuba算法原理是利用
( A x 2 n + B ) ( C x 2 n + D ) = A C x n + ( ( A + B ) ( C + D ) − A C − B D ) x 2 n + B D \ \ \ \ (Ax^{\frac 2n}+B)(Cx^{\frac 2n}+D)\\=ACx^n+((A+B)(C+D)-AC-BD)x^{\frac 2n}+BD (Axn2+B)(Cxn2+D)=ACxn+((A+B)(C+D)−AC−BD)xn2+BD
不断递归减少乘法次数。
而 F F T / N T T FFT/ NTT FFT/NTT的基本思想都是利用单位复根/单位原根并采用分治策略先将 f ( x ) , g ( x ) f(x),g(x) f(x),g(x)转化为点值表示,在点值上处理为 h ( x ) h(x) h(x)的点值表示(显然 f ( a ) g ( a ) = h ( a ) f(a)g(a)=h(a) f(a)g(a)=h(a)),再转化为 h ( x ) h(x) h(x),因为 F F T FFT FFT中涉及大量虚数实数运算,精度和常数都很感人,所以常用单模数 N T T NTT NTT,但限制模数为质数。
这里假设大家都已经会 F F T , N T T FFT,NTT FFT,NTT,就不详细展开了。
这里先给出 N T T NTT NTT代码(下文省略),以及习惯性模运算优化:
inline void NTT(int *e,int ptr,int len)//ptr=1 正变换 ptr=0 逆变换
{
int i,j,k,ori,G,pd,ix,iy;G= ptr? g:inv[g];//g:原根 inv[g]:g的逆元
for(i=1;i<len;++i) if(i<rv[i]) swap(e[i],e[rv[i]]);
for(i=1;i<len;i<<=1){
ori=fp(G,(mod-1)/(i<<1));
for(j=0;j<len;j+=(i<<1)){
pd=1;
for(k=0;k<i;++k,pd=mul(pd,ori)){
ix=e[j+k];iy=mul(e[i+j+k],pd);
e[j+k]=ad(ix,iy);e[i+j+k]=dc(ix,iy);
}
}
}
if(ptr) return;
for(i=0;i<len;++i) e[i]=mul(e[i],inv[len]);
}
inline int ad(int x,int y) {
x+=y;if(x>=mod) x-=mod;return x;}
inline int dc(int x,int y) {
x-=y;if(x<0) x+=mod;return x;}
inline int mul(int x,int y) {
return 1ll*x*y%mod;}
牛顿迭代
解近似方程根 h ( x ) = 0 h(x)=0 h(x)=0的一种方法。
设 h ( x ) h(x) h(x)当前近似解为 x n x_n xn,进一步迭代:
x n + 1 = x n − h ( x n ) h ′ ( x n ) x n x_{n+1}=x_n-\dfrac {h(x_n)}{\frac {h'(x_n)}{x_n}} xn+1=xn−xnh′(xn)h(xn)
引申:当 h ( x ) h(x) h(x)中嵌套一个 f ( x ) f(x) f(x)构成复合函数 h ( f ( x ) ) = 0 h(f(x))=0 h(f(x))=0,同样可以牛顿迭代倍增求解近似的 f ( x ) f(x) f(x),满足 g ( x ) ≡ h ( f n ( x ) ) ≡ 0 ( m o d x 2 n ) g(x)\equiv h(f_n(x))\equiv 0(mod \ x^{2^n}) g(x)≡h(fn(x))≡0(mod x2n)。
f n + 1 ( x ) ≡ f n ( x ) − g ( x ) g ′ ( x ) ( m o d x 2 n + 1 ) f_{n+1}(x)\equiv f_n(x)-\dfrac {g(x)}{ {g'(x)}{}}(mod\ x^{2^{n+1}}) fn+1(x)≡fn(x)−g′(x)g(x)(mod x2n+1)
注: g ′ ( x ) g'(x) g′(x)是 g g g对 h h h的偏导, g ′ ( x ) = h ′ ( f n ( x ) ) g'(x)=h'(f_n(x)) g′(x)=h′(fn(x))。
上式可以用泰勒展开证明当 f n ( x ) f_n(x) f