概述
PS:洛谷上有大部分以下操作的模板题。
感谢 cyk 巨神 的 多项式算法合集。
多项式求逆
problem:
给定一个 ( n − 1 ) (n-1) (n−1) 次多项式 A ( x ) A(x) A(x) ,求多项式 B ( x ) B(x) B(x) 满足:
A ( x ) B ( x ) ≡ 1 ( m o d x n ) A(x)B(x)≡1(,mathrm{mod}; x^n) A(x)B(x)≡1(modxn)
solution:
为了方便,我们设 n = 2 k ( k > 0 ) n=2^k(k>0) n=2k(k>0)(若 n n n 不是 2 2 2 的整数次幂,可以像 f f t fft fft 那样强行扩大到 2 k 2^k 2k)。
用类似于倍增的方法,即假设我们已知
A ( x ) C ( x ) ≡ 1 ( m o d x n 2 ) A(x)C(x)equiv1(,mathrm{mod};x^{frac n 2}) A(x)C(x)≡1(modx2n)
因为 A ( x ) B ( x ) ≡ 1 ( m o d x n ) A(x)B(x)≡1(,mathrm{mod}; x^n) A(x)B(x)≡1(modxn),那么有 A ( x ) B ( x ) ≡ 1 ( m o d x n 2 ) A(x)B(x)≡1(,mathrm{mod}; x^{frac n 2}) A(x)B(x)≡1(modx2n),两式相减得:
A ( x ) ( B ( x ) − C ( x ) ) ≡ 0 ( m o d x n 2 ) A(x)(B(x)-C(x))equiv 0(,mathrm{mod};x^{frac n 2}) A(x)(B(x)−C(x))≡0(modx2n)
那么消掉 A ( x ) A(x) A(x),两边平方得:
B 2 ( x ) + C 2 ( x ) − 2 B ( x ) C ( x ) ≡ 0 ( m o d x n ) B^2(x)+C^2(x)-2B(x)C(x)equiv0(,mathrm{mod};x^n) B2(x)+C2(x)−2B(x)C(x)≡0(modxn)
这个时候再把 A ( x ) A(x) A(x) 乘回去,得到:
A ( x ) ( B 2 ( x ) + C 2 ( x ) − 2 B ( x ) C ( x ) ) ≡ 0 ( m o d x n ) A(x)(B^2(x)+C^2(x)-2B(x)C(x))equiv0(,mathrm{mod};x^n) A(x)(B2(x)+C2(x)−2B(x)C(x))≡0(modxn)
然后再综合 A ( x ) B ( x ) ≡ 1 ( m o d x n ) A(x)B(x)equiv1(,mathrm{mod};x^n) A(x)B(x)≡1(modxn) 化简,最终得到:
B ( x ) = 2 C ( x ) − A ( x ) C 2 ( x ) ( m o d x n ) B(x)=2C(x)-A(x)C^2(x)(,mathrm{mod};x^n) B(x)=2C(x)−A(x)C2(x)(modxn)
时间复杂度 O ( n log n ) O(nlog n) O(nlogn)。
code:
注意代码中用的变量和推导中用的不一样。
typedef vector<int> poly;
poly Inv(poly A,int len){
poly C,B(1,Power(A[0],P-2));
for(int limit=4;limit<(len<<2);limit<<=1){
init(limit);
C=A,C.resize(limit>>1);
C.resize(limit),NTT(C,limit,1);
B.resize(limit),NTT(B,limit,1);
for(int i=0;i<limit;++i)
B[i]=mul(B[i],dec(2,mul(B[i],C[i])));
NTT(B,limit,-1),B.resize(limit>>1);
}
B.resize(len);return B;
}
多项式开根
problem:
已知一个 ( n − 1 ) (n-1) (n−1) 次多项式 A ( x ) A(x) A(x),求多项式 B ( x ) B(x) B(x) 满足
B 2 ( x ) ≡ A ( x ) ( m o d x n ) B^2(x)≡A(x)(,mathrm{mod} ;x^n) B2(x)≡A(x)(modxn)
保证 A ( 0 ) = 1 A(0)=1 A(0)=1。
solution:
和求逆一样,为了方便,记 n = 2 k ( k > 0 ) n=2^k(k>0) n=2k(k>0)。
假设我们知道
C 2 ( x ) ≡ A ( x ) ( m o d x n 2 ) C^2(x)equiv A(x)(,mathrm{mod} ;x^{frac n 2}) C2(x)≡A(x)(modx2n)
因为 B 2 ( x ) ≡ A ( x ) ( m o d x n ) B^2(x)≡A(x)(,mathrm{mod}; x^n) B2(x)≡A(x)(modxn),那么有 B 2 ( x ) ≡ A ( x ) ( m o d x n 2 ) B^2(x)≡A(x)(,mathrm{mod}; x^{frac n 2}) B2(x)≡A(x)(modx2n),那么
B ( x ) − C ( x ) ≡ 0 ( m o d x n 2 ) B(x)-C(x)equiv0(,mathrm{mod} ;x^{frac n 2}) B(x)−C(x)≡0(modx2n)
平方,得:
B 2 ( x ) + C 2 ( x ) − 2 B ( x ) C ( x ) ≡ 0 ( m o d x n ) B^2(x)+C^2(x)-2B(x)C(x)equiv0(,mathrm{mod};x^n) B2(x)+C2(x)−2B(x)C(x)≡0(modxn)
又由于 B 2 ( x ) ≡ A ( x ) ( m o d x n ) B^2(x)equiv A(x)(,mathrm{mod};x^n) B2(x)≡A(x)(modxn),所以:
B ( x ) = A ( x ) 2 C ( x ) + C ( x ) 2 ( m o d x n ) B(x)=frac{A(x)}{2C(x)}+frac{C(x)}{2}(,mathrm{mod};x^n) B(x)=2C(x)A(x)+2C(x)(modxn)
不难发现需要用到上面所说的多项式求逆。
时间复杂度
O
(
n
log
n
)
O(nlog n)
O(nlogn),好像常数有点大。
code:
typedef vector<int> poly;
poly Sqrt(poly A,int len){
poly B(1,1),C,D;
for(int limit=4;limit<(len<<2);limit<<=1){
C=A,C.resize(limit>>1);
init(limit),D=Inv(B,limit>>1);
C.resize(limit),NTT(C,limit,1);
D.resize(limit),NTT(D,limit,1);
for(int i=0;i<limit;++i)
C[i]=mul(C[i],D[i]);
NTT(C,limit,-1),B.resize(limit>>1);
for(int i=0;i<(limit>>1);++i)
B[i]=mul(inv2,add(B[i],C[i]));
}
B.resize(len);return B;
}
多项式除法 & & & 取模
problem:
给定一个 n n n 次多项式 A ( x ) A(x) A(x) 和一个 m m m 次多项式 B ( x ) B(x) B(x),求一个 ( n − m ) (n-m) (n−m) 次多项式 C ( x ) C(x) C(x) 和 ( m − 1 ) (m-1) (m−1) 次多项式 D ( x ) D(x) D(x) 满足:
A ( x ) = B ( x ) C ( x ) + D ( x ) A(x)=B(x)C(x)+D(x) A(x)=B(x)C(x)+D(x)
solution:
对于一个最高项次数为 n n n 的多项式 A ( x ) A(x) A(x),我们考虑对它进行一个操作,即令 A R ( x ) = x n A ( 1 x ) A^R(x)=x^nA(frac 1 x) AR(x)=xnA(x1)。
发现 A R ( x ) A^R(x) AR(x) 就是将 A ( x ) A(x) A(x) 的系数反转的式子(可以代几个 n n n 比较小的多项式来帮助自己理解)。
现在的式子是:
A ( x ) = B ( x ) C ( x ) + D ( x ) A(x)=B(x)C(x)+D(x) A(x)=B(x)C(x)+D(x)
其中, A ( x ) A(x) A(x) 最高项为 n n n, B ( x ) B(x) B(x) 最高项为 m m m, C ( x ) C(x) C(x) 最高项为 n − m n-m n−m, D ( x ) D(x) D(x) 的最高项为 m − 1 m-1 m−1。
那么两边同时乘 x n x^n xn,并将 1 x frac 1 x x1 代入,得到:
x n A ( 1 x ) = x m B ( 1 x ) x n − m C ( 1 x ) + x n − m + 1 × x m − 1 D ( 1 x ) x^nA(frac 1 x)=x^mB(frac 1 x)x^{n−m}C(frac 1 x)+x^{n−m+1}times x^{m−1}D(frac 1 x) xnA(x1)=xmB(x1)xn−mC(x1)+xn−m+1×xm−1D(x1)
通过上面的公式,即 A R ( x ) = x n A ( 1 x ) A^R(x)=x^nA(frac 1 x) AR(x)=xnA(x1),得到:
A R ( x ) = B R ( x ) C R ( x ) + x n − m + 1 D R ( x ) A^R(x)=B^R(x)C^R(x)+x^{n-m+1}D^R(x) AR(x)=BR(x)CR(x)+xn−m+1DR(x)
考虑在 m o d x n − m + 1 mathrm{mod}; x^{n−m+1} modxn−m+1 意义下, A , B A,B A,B 已知, C C C 最高为 n − m n-m n−m 不影响,而 D D D 被消去。
所以我们有:
A R ( x ) ≡ B R ( x ) C R ( x ) ( m o d x n − m + 1 ) A^R(x)equiv B^R(x)C^R(x)(,mathrm{mod};x^{n-m+1}) AR(x)≡BR(x)CR(x)(modxn−m+1)
用多项式求逆即可解出 C R ( x ) C^R(x) CR(x),也就解出了 C ( x ) C(x) C(x)。
最后把 C ( x ) C(x) C(x) 代回去就可以解出 D ( x ) D(x) D(x)。
复杂度 O ( n log n ) O(nlog n) O(nlogn)。
code:
PS:代码中多项式的 ∗ * ∗ 和 − - − 是重载过的。
typedef vector<int> poly;
poly operator/(poly A,poly B){
int limit=1,len=A.size()-B.size()+1;
reverse(A.begin(),A.end());
reverse(B.begin(),B.end());
while(limit<=len)
limit<<=1;
B=Inv(B,limit),B.resize(len);
A=A*B,A.resize(len);
reverse(A.begin(),A.end());
return A;
}
poly operator%(poly A,poly B){
poly C=A-(A/B)*B;
C.resize(B.size()-1);
return C;
}
多项式微积分(求导 & & & 积分)
solution:
令 f ( x ) = x n f(x)=x^n f(x)=xn,那么它的导数 f ′ ( x ) = n x n − 1 f'(x)=nx^{n-1} f′(x)=nxn−1,根据这个可以快速求多项式的导数。
证明如下:
首先根据导数定义,有:f ′ ( x ) = lim Δ x → 0 ( x + Δ x ) n − x n Δ x f'(x)=lim_{Delta xrightarrow 0}frac{(x+Delta x)^n-x^n}{Delta x} f′(x)=Δx→0limΔx(x+Δx)n−xn
用二项式定理展开,得到:
f ′ ( x ) = lim Δ x → 0 ∑ i = 0 n ( n i ) x i Δ x n − i − x n Δ x = lim Δ x → 0 ∑ i = 0 n − 1 ( n i ) x i Δ x n − i + x n Δ x 0 − x n Δ x = lim Δ x → 0 ∑ i = 0 n − 1 ( n i ) x i Δ x n − i − 1 = lim Δ x → 0 ∑ i = 0 n − 2 ( n i ) x i Δ x n − i − 1 + ( n n − 1 ) x n − 1 begin{aligned} f'(x)&=lim_{Delta xrightarrow 0}frac{sum_{i=0}^nbinom n ix^iDelta x^{n-i}-x^n}{Delta x}\ &=lim_{Delta xrightarrow 0}frac{sum_{i=0}^{n-1}binom n ix^iDelta x^{n-i}+x^nDelta x^0-x^n}{Delta x}\ &=lim_{Delta xrightarrow 0}sum_{i=0}^{n-1}binom n ix^iDelta x^{n-i-1}\ &=lim_{Delta xrightarrow 0}sum_{i=0}^{n-2}binom n ix^iDelta x^{n-i-1}+binom n {n-1}x^{n-1} end{aligned} f′(x)=Δx→0limΔx∑i=0n(in)xiΔxn−i−xn=Δx→0limΔx∑i=0n−1(in)xiΔxn−i+xnΔx0−xn=Δx→0limi=0∑n−1(in)xiΔxn−i−1=Δx→0limi=0∑n−2(in)xiΔxn−i−1+(n−1n)xn−1
又由于有限个无穷小的乘积依旧是无穷小,所以得到:
f ′ ( x ) = ( n n − 1 ) x n − 1 = n x n − 1 f'(x)=binom n {n-1}x^{n-1}=nx^{n-1} f′(x)=(n−1n)xn−1=nxn−1
证毕。
积分好像可以简单理解为导数的逆运算,还不是很会。。。
code:
PS:inv 数组是预处理的逆元。
typedef vector<int> poly;
poly Deriv(poly A){
for(int i=0;i<A.size()-1;++i)
A[i]=mul(A[i+1],i+1);
A.pop_back();return A;
}
poly Integ(poly A){
A.push_back(0);
for(int i=A.size()-1;i;--i)
A[i]=mul(A[i-1],inv[i]);
A[0]=0;return A;
}
多项式 Ln
problem:
给出 ( n − 1 ) (n-1) (n−1) 次多项式 A ( x ) A(x) A(x),求一个 m o d x n bmod{:x^n} modxn 下的多项式 B ( x ) B(x) B(x),满足:
B ( x ) ≡ ln A ( x ) ( m o d x n ) B(x) equiv ln A(x)(bmod ;x^n) B(x)≡lnA(x)(modxn)
保证 A ( 0 ) = 1 A(0)=1 A(0)=1。
solution:
有一个结论,即若 B ( x ) = ln A ( x ) B(x) = ln A(x) B(x)=lnA(x),则 A ′ ( x ) = A ( x ) B ′ ( x ) A'(x)=A(x)B'(x) A′(x)=A(x)B′(x)。
证明如下:
首先有链式法则,即对于复合函数 ( g ∘ f ) ( x ) = g ( f ( x ) ) (gcirc f)(x)=g(f(x)) (g∘f)(x)=g(f(x)),有 ( g ∘ f ) ′ ( x ) = g ′ ( f ( x ) ) f ′ ( x ) (gcirc f)'(x)=g'(f(x))f'(x) (g∘f)′(x)=g′(f(x))f′(x)。
那么对于 B ( x ) = ln A ( x ) B(x)=ln A(x) B(x)=lnA(x),两边同时求导,得到 B ′ ( x ) = ( ln A ( x ) ) ′ B'(x)=(ln A(x))' B′(x)=(lnA(x))′。
等式右边可以看做一个复合函数,用链式法则化简后就是 ( ln ′ A ( x ) ) A ′ ( x ) = A ′ ( x ) A ( x ) (ln' A(x))A'(x)=frac{A'(x)}{A(x)} (ln′A(x))A′(x)=A(x)A′(x)。
带回去,即可得到 A ′ ( x ) = A ( x ) B ′ ( x ) A'(x)=A(x)B'(x) A′(x)=A(x)B′(x)。
证毕。
那么 B ′ ( x ) = A ′ ( x ) A ( x ) B'(x)=frac{A'(x)}{A(x)} B′(x)=A(x)A′(x),给 A ( x ) A(x) A(x) 求逆、求导就可以算出 B ′ ( x ) B'(x) B′(x)。
然后再对 B ′ ( x ) B'(x) B′(x) 积分就能解出 B ( x ) B(x) B(x)。
code:
typedef vector<int> poly;
poly Ln(poly A,int len){
A=Integ(Deriv(A)*Inv(A,len)),A.resize(len);
return A;
}
多项式 Exp
前置知识 1 1 1:泰勒展开
泰勒展开是将一个在 x = x 0 x=x_0 x=x0 处具有 n n n 阶导数的函数 f ( x ) f(x) f(x) 利用关于 ( x − x 0 ) (x-x_0) (x−x0) 的 n n n 次多项式来逼近函数的方法。
若函数 f ( x ) f(x) f(x) 在包含 x 0 x_0 x0 的某个闭区间 [ a , b ] [a,b] [a,b] 上具有 n n n 阶导数,且在开区间 ( a , b ) (a,b) (a,b) 上具有 ( n + 1 ) (n+1) (n+1) 阶导数,则对闭区间 [ a , b ] [a,b] [a,b] 上任意一点 x x x,下式成立:
f ( x ) = f ( x 0 ) 0 ! + f ′ ( x 0 ) 1 ! ( x − x 0 ) + f ′ ′ ( x 0 ) 2 ! ( x − x 0 ) 2 + ⋯ + f ( n ) ( x 0 ) n ! ( x − x 0 ) n + ⋯ f(x)=frac{f(x_0)}{0!}+frac{f'(x_0)}{1!}(x-x_0)+frac{f''(x_0)}{2!}(x-x_0)^2+cdots+frac{f^{(n)}(x_0)}{n!}(x-x_0)^n+cdots f(x)=0!f(x0)+1!f′(x0)(x−x0)+2!f′′(x0)(x−x0)2+⋯+n!f(n)(x0)(x−x0)n+⋯
我简单说一下我理解的泰勒展开。
等式右边的式子是一个多项式,所以我们的目标就是找一个多项式 g ( x ) g(x) g(x),使它与 f ( x ) f(x) f(x) 完全相同。
首先我们保证初始点 g ( x 0 ) = f ( x 0 ) g(x_0)=f(x_0) g(x0)=f(x0)。
在此基础上,考虑曲线的变化趋势,即导数,保证在此处的导数相同,即 g ′ ( x 0 ) = f ′ ( x 0 ) g'(x_0)=f'(x_0) g′(x0)=f′(x0)。
要进一步精确化,再考虑凹凸性,由于表征图像的凹凸性的参数为导数的导数,我们让二者导数的导数相等,即 g ′ ′ ( x 0 ) = f ′ ′ ( x 0 ) g''(x_0)=f''(x_0) g′′(x0)=f′′(x0)。
那么以此类推,继续精确,让 x 0 x_0 x0 更高阶的导数相等,即 g ( n ) ( x 0 ) = f ( n ) ( x 0 ) g^{(n)}(x_0)=f^{(n)}(x_0) g(n)(x0)=f(n)(x0)。
上面的式子归纳一下,就是 ∀ i , g ( i ) ( x 0 ) = f ( i ) ( x 0 ) forall i,g^{(i)}(x_0)=f^{(i)}(x_0) ∀i,g(i)(x0)=f(i)(x0)。
因为 x n x^n xn 的导数为 n x n − 1 nx^{n-1} nxn−1,所以求 g ( x ) g(x) g(x) 第 i i i 阶导数时为 a i × i ! = f ( i ) ( x 0 ) a_itimes i!=f^{(i)}(x_0) ai×i!=f(i)(x0),所以 a i = f ( i ) ( x 0 ) i ! a_i=frac{f^{(i)}(x_0)}{i!} ai=i!f(i)(x0)。
可以看看这个,对理解泰勒展开会有帮助。
前置知识 2 2 2:牛顿迭代
摘自 Miskcoo’s Space 的牛顿迭代法在多项式运算的应用。
有这样一个问题,即已知一个函数 g ( x ) g(x) g(x),求一个多项式 f ( x ) m o d x n f(x)bmod ;x^n f(x)modxn,满足方程
g ( f ( x ) ) ≡ 0 ( m o d x n ) g(f(x))≡0(bmod;x^n) g(f(x))≡0(modxn)
首先在 n = 1 n=1 n=1 的时候, g ( f ( x ) ) ≡ 0 ( m o d x ) g(f(x))≡0(bmod;x) g(f(x))≡0(modx),这是可以直接求出来的。
现在假设已经求出了 g ( f 0 ( x ) ) ≡ 0 ( m o d x ⌈ n 2 ⌉ ) g(f_0(x))≡0(bmod;x^{⌈frac n 2⌉}) g(f0(x))≡0(modx⌈2n⌉),考虑如何扩展到 m o d x n bmod;x^n modxn 下。
我们把 g ( f ( x ) ) g(f(x)) g(f(x)) 在 f 0 ( x ) f_0(x) f0(x) 进行泰勒展开,得到:
g ( f ( x ) ) = g ( f 0 ( x ) ) + g ′ ( f 0 ( x ) ) 1 ! ( f ( x ) − f 0 ( x ) ) + g ′ ′ ( f 0 ( x ) ) 2 ! ( f ( x ) − f 0 ( x ) ) 2 + ⋯ g(f(x))=g(f_0(x))+frac{g'(f_0(x))}{1!}(f(x)−f_0(x))+frac{g''(f_0(x))}{2!}(f(x)−f_0(x))^2+⋯ g(f(x))=g(f0(x))+1!g′(f0(x))(f(x)−f0(x))+2!g′′(f0(x))(f(x)−f0(x))2+⋯
首先显然有 f ( x ) ≡ f 0 ( x ) ( m o d x ⌈ n 2 ⌉ ) f(x)≡f_0(x)(bmod ;x^{⌈frac n 2⌉}) f(x)≡f0(x)(modx⌈2n⌉),所以 f ( x ) − f 0 ( x ) f(x)-f_0(x) f(x)−f0(x) 最低项次数一定大于 ⌈ n 2 ⌉ lceil frac n 2rceil ⌈2n⌉。因此在 m o d x n bmod ;x^n modxn 意义下,整个式子从 ( f ( x ) − f 0 ( x ) ) 2 (f(x)−f_0(x))^2 (f(x)−f0(x))2 这一项开始都为 0 0 0 了,也即:
g ( f ( x ) ) ≡ g ( f 0 ( x ) ) + g ′ ( f 0 ( x ) ) ( f ( x ) − f 0 ( x ) ) ( m o d x n ) g(f(x))≡g(f_0(x))+g'(f_0(x))(f(x)−f_0(x))(bmod ;x^n) g(f(x))≡g(f0(x))+g′(f0(x))(f(x)−f0(x))(modxn)
又因为 g ( f ( x ) ) ≡ 0 ( m o d x n ) g(f(x))≡0(bmod;x^n) g(f(x))≡0(modxn),得到
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))}(bmod;x^n) f(x)≡f0(x)−g′(f0(x))g(f0(x))(modxn)
这样就大功告成了。
OK,下面就步入正题,多项式 Exp。
problem:
给出 ( n − 1 ) (n-1) (n−1) 次多项式 A ( x ) A(x) A(x),求一个 m o d x n bmod{;x^n} modxn 下的多项式 B ( x ) B(x) B(x),满足:
B ( x ) ≡ e A ( x ) ( m o d x n ) B(x) equiv e^{A(x)}(bmod;x^n) B(x)≡eA(x)(modxn)
保证 A ( 0 ) = 0 A(0)=0 A(0)=0。
solution:
发现原问题可以转化一下,即求解:
ln B ( x ) ≡ A ( x ) ( m o d x n ) ln B(x)equiv A(x)(bmod ; x^n) lnB(x)≡A(x)(modxn)
还是令 n = 2 k n=2^k n=2k,假设我们已经知道了 ln B 0 ( x ) − A ( x ) ≡ 0 ( m o d x n 2 ) ln B_0(x)-A(x)equiv 0(bmod;x^{frac n 2}) lnB0(x)−A(x)≡0(modx2n)。
构造 P ( B ( x ) ) = ln B ( x ) − A ( x ) P(B(x))=ln B(x)-A(x) P(B(x))=lnB(x)−A(x),那么 P ′ ( B ( x ) ) = 1 B ( x ) P'(B(x))=frac{1}{B(x)} P′(B(x))=B(x)1
那么按照牛顿迭代的推理可得:
B ( x ) ≡ B 0 ( x ) − P ( B 0 ( x ) ) P ′ ( B 0 ( x ) ) ≡ B 0 ( x ) ( 1 − ln B 0 ( x ) + A ( x ) ) ( m o d x n ) B(x)≡B_0(x)− frac{P(B_0(x))}{P'(B_0(x))}≡B_0(x)(1−ln B_0(x)+A(x))(bmod ;x^n) B(x)≡B0(x)−P′(B0(x))P(B0(x))≡B0(x)(1−lnB0(x)+A(x))(modxn)
时间复杂度 O ( n log n ) O(nlog n) O(nlogn)。
code:
typedef vector<int> poly;
poly Exp(poly A,int len){
poly B(1,1),C;A.resize(len<<1);
for(int limit=2;limit<(len<<1);limit<<=1){
C=Ln(B,limit);
for(int i=0;i<limit;++i)
C[i]=dec(A[i],C[i]);
C[0]=add(C[0],1),B=B*C;
B.resize(limit);
}
B.resize(len);return B;
}
多项式快速幂
problem:
给定一个 ( n − 1 ) (n-1) (n−1) 次多项式 A ( x ) A(x) A(x),求一个在 m o d x n bmod; x^n modxn 意义下的多项式 B ( x ) B(x) B(x),满足:
B ( x ) ≡ A k ( x ) ( m o d x n ) B(x) equiv A^k(x) (bmod; x^n) B(x)≡Ak(x) (modxn)
保证 A ( 0 ) = 1 A(0)=1 A(0)=1。
solution:
如果直接用快速幂+ n t t ntt ntt的话,时间复杂度是 O ( n log 2 n ) O(nlog^2n) O(nlog2n) 的,而且常数还比较大。
所以我们换一种方法,即发现:
A k ( x ) = ( e ln A ( x ) ) k = e k × ln A ( x ) A^k(x)=(e^{ln A(x)})^k=e^{ktimes ln A(x)} Ak(x)=(elnA(x))k=ek×lnA(x)
所以我们用多项式 Ln,Exp 就可以了。
时间复杂度 O ( n log n ) O(nlog n) O(nlogn)。
code:
typedef vector<int> poly;
poly Power(poly A,int len,int k){
A=Exp(Ln(A,len)*k,len),A.resize(len);
return A;
}
多项式多点求值
problem:
给定一个 n n n 次多项式 f ( x ) f(x) f(x),并给出 m m m 个整数 a i a_i ai,请你对于 ∀ i ∈ [ 1 , m ] forall i in [1,m] ∀i∈[1,m],求出 f ( a i ) f(a_i) f(ai)。
solution:
首先,根据余式定理,我们有:
f ( x ) ≡ f ( x 0 ) ( m o d ( x − x 0 ) ) f(x)equiv f(x_0)(bmod;(x-x_0)) f(x)≡f(x0)(mod(x−x0))
简单写一下它的证明:
令 f ( x ) = g ( x ) ( x − x 0 ) + A ( x ) f(x)=g(x)(x-x_0)+A(x) f(x)=g(x)(x−x0)+A(x),那么 A ( x ) A(x) A(x) 为就是 f ( x ) f(x) f(x) 对 ( x − x 0 ) (x-x_0) (x−x0) 取模的结果,即 f ( x ) ≡ A ( x ) ( m o d ( x − x 0 ) ) f(x)equiv A(x)(bmod (x-x_0)) f(x)≡A(x)(mod(x−x0))。
由于 ( x − x 0 ) (x-x_0) (x−x0) 的最高项次数为 1 1 1,所以 A ( x ) A(x) A(x) 最高项次数为 0 0 0,即为常数项。
把 x 0 x_0 x0 代入 f ( x ) f(x) f(x),得到 f ( x 0 ) = g ( x 0 ) ( x 0 − x 0 ) + A ( x 0 ) = A ( x ) f(x_0)=g(x_0)(x_0-x_0)+A(x_0)=A(x) f(x0)=g(x0)(x0−x0)+A(x0)=A(x),所以就有 f ( x ) ≡ f ( x 0 ) ( m o d ( x − x 0 ) ) f(x)equiv f(x_0)(bmod;(x-x_0)) f(x)≡f(x0)(mod(x−x0))。
但是直接这样做是不行的,对于一个点,多项式取模是 O ( n log n ) O(nlog n) O(nlogn) 的,甚至比 O ( n ) O(n) O(n) 的暴力还慢。
然后考虑用分治优化。
令 G l , r ( x ) = ∏ i = l r ( x − x i ) G_{l,r}(x)=prodlimits_{i=l}^{r}(x-x_i) Gl,r(x)=i=l∏r(x−xi),我们现在已经算出了 f ( x ) ≡ A ( x ) ( m o d ∏ i = l r ( x − x i ) ) f(x)equiv A(x)pmod{prodlimits_{i=l}^r(x-x_i)} f(x)≡A(x)(modi=l∏r(x−xi)),因此只需要用 A ( x ) A(x) A(x) 分别对 G l , ⌊ l + r 2 ⌋ ( x ) G_{l,lfloorfrac{l+r}{2}rfloor}(x) Gl,⌊2l+r⌋(x) 和 G ⌊ l + r 2 ⌋ + 1 , r ( x ) G_{lfloorfrac{l+r}{2}rfloor+1,r}(x) G⌊2l+r⌋+1,r(x) 取模,再递归下去。分治到叶子的时候,就只剩下 f ( x ) ≡ A ( x ) ( m o d ( x − x i ) ) f(x)equiv A(x)pmod{(x-x_i)} f(x)≡A(x)(mod(x−xi)),此时的 A ( x ) A(x) A(x) 就是 i i i 的答案。
每个 G ( x ) G(x) G(x) 可以提前分治 n t t ntt ntt预处理出来。
时间复杂度 T ( n ) = T ( n 2 ) + O ( n log n ) = O ( n log 2 n ) T(n)=T(frac{n}{2})+O(nlog n)=O(nlog^2 n) T(n)=T(2n)+O(nlogn)=O(nlog2n)。
不知道为什么跑得贼慢,也许是我自带大常数吧。
code:
typedef vector<int> poly;
poly F,G[N];
void build(int root,int l,int r){
if(l==r){
G[root].clear();
G[root].push_back(P-a[l]),G[root].push_back(1);
return;
}
int mid=(l+r)>>1;
build(root<<1,l,mid),build(root<<1|1,mid+1,r);
G[root]=G[root<<1]*G[root<<1|1];
}
void calc(int root,int l,int r,poly now){
if(l==r)
{ans[l]=now[0];return;}
int mid=(l+r)>>1;
calc(root<<1,l,mid,now%G[root<<1]);
calc(root<<1|1,mid+1,r,now%G[root<<1|1]);
}
多项式快速插值
前置知识 1 1 1:拉格朗日插值
给定 ( n + 1 ) (n+1) (n+1) 个点 ( x i , y i ) (x_i,y_i) (xi,yi),其中每个 x x x 互不相同,那么存在唯一的次数不超过 n n n 的多项式 f ( x ) f(x) f(x),满足 ∀ i ∈ [ 1 , n ] forall iin [1,n] ∀i∈[1,n], f ( x i ) = y i f(x_i)=y_i f(xi)=yi,即:
f ( x ) = ∑ i = 1 n y i ∏ j ≠ i x − x j x i − x j f(x)=sum_{i=1}^ny_iprod_{jne i}frac{x-x_j}{x_i-x_j} f(x)=i=1∑nyij=i∏xi−xjx−xj
这个应该比较显然,因为对于 x k x_k xk,只有当上式中 i = k i=k i=k 时 ∏ j ≠ i x − x j x i − x j = 1 prod_{jne i}frac{x-x_j}{x_i-x_j}=1 ∏j=ixi−xjx−xj=1,否则是 0 0 0。
前置知识 2 2 2:洛必达法则
若 lim x → a f ( x ) = 0 limlimits_{xrightarrow a}f(x)=0 x→alimf(x)=0, lim x → a g ( x ) = 0 limlimits_{xrightarrow a}g(x)=0 x→alimg(x)=0,在点 a a a 的某去心邻域内两者都可导,且 g ′ ( x ) ≠ 0 g'(x)ne 0 g′(x)=0,那么有:
lim x → a f ( x ) g ( x ) = lim x → a f ′ ( x ) g ′ ( x ) lim_{xrightarrow a}frac{f(x)}{g(x)}=lim_{xrightarrow a}frac{f'(x)}{g'(x)} x→alimg(x)f(x)=x→alimg′(x)f′(x)
接下来回到我们的问题。
problem:
给出 n n n 个点 ( x i , y i ) (x_i, y_i) (xi,yi),求一个 n − 1 n-1 n−1 次的多项式 f ( x ) f(x) f(x),使得 f ( x i ) ≡ y i ( m o d 998244353 ) f(x_i)equiv y_ipmod{998244353} f(xi)≡yi(mod998244353)。
solution:
考虑到直接用求拉格朗日插值是 O ( n 2 ) O(n^2) O(n2) 的,我们把它变一下形:
f ( x ) = ∑ i = 1 n y i ∏ j ≠ i ( x i − x j ) ∏ j ≠ i ( x − x j ) f(x)=sum_{i=1}^nfrac{y_i}{prod_{jne i}(x_i-x_j)}prod_{jne i} (x-x_j) f(x)=i=1∑n∏j=i(xi−xj)yij=i∏(x−xj)
考虑先求出 G = ∏ j ≠ i ( x i − x j ) G=prod_{jne i}(x_i-x_j) G=∏j=i(xi−xj)。
令 g ( x ) = ∏ j = 1 n ( x − x j ) g(x)=prod_{j=1}^n(x-x_j) g(x)=∏j=1n(x−xj),那么 j ≠ i jne i j=i 的限制就相当于除了个 x − x i x-x_i x−xi,所以 G = g ( x i ) x − x i G=frac{g(x_i)}{x-x_i} G=x−xig(xi)。
发现这时分子分母都是 0 0 0,根据洛必达法则,有 G = g ′ ( x i ) 1 = g ′ ( x i ) G=frac{g'(x_i)}{1}=g'(x_i) G=1g′(xi)=g′(xi)。
接下来考虑分治优化,设 f l , r f_{l,r} fl,r 表示 [ l , r ] [l,r] [l,r] 的答案, m i d = ⌊ l + r 2 ⌋ mid=lfloorfrac{l+r}{2}rfloor mid=⌊2l+r⌋,那么有:
f l , r = ∑ i = l r y i g ′ ( x i ) ∏ j = l r [ j ≠ i ] ( x − x j ) = ∏ k = m i d + 1 r ( x − x k ) ∑ i = l m i d y i g ′ ( x i ) ∏ j = l m i d [ j ≠ i ] ( x − x j ) + ∏ k = l m i d ( x − x k ) ∑ i = m i d + 1 r y i g ′ ( x i ) ∏ j = m i d + 1 r [ j ≠ i ] ( x − x j ) = f l , m i d ∏ k = m i d + 1 r ( x − x k ) + f m i d + 1 , r ∏ k = l m i d ( x − x k ) begin{aligned} f_{l,r}&=sum_{i=l}^rfrac{y_i}{g'(x_i)}prod_{j=l}^{r}[jne i](x-x_j)\ &=prod _{k=mid+1}^r(x-x_k)sum_{i=l}^{mid}frac{y_i}{g'(x_i)}prod_{j=l}^{mid}[jne i](x-x_j)+prod _{k=l}^{mid}(x-x_k)sum_{i=mid+1}^rfrac{y_i}{g'(x_i)}prod_{j=mid+1}^{r}[jne i](x-x_j)\ &=f_{l,mid}prod _{k=mid+1}^r(x-x_k)+f_{mid+1,r}prod _{k=l}^{mid}(x-x_k) end{aligned} fl,r=i=l∑rg′(xi)yij=l∏r[j=i](x−xj)=k=mid+1∏r(x−xk)i=l∑midg′(xi)yij=l∏mid[j=i](x−xj)+k=l∏mid(x−xk)i=mid+1∑rg′(xi)yij=mid+1∏r[j=i](x−xj)=fl,midk=mid+1∏r(x−xk)+fmid+1,rk=l∏mid(x−xk)
其实就是把 f l , r f_{l,r} fl,r 拆成 f l , m i d f_{l,mid} fl,mid 和 f m i d + 1 , r f_{mid+1,r} fmid+1,r 的式子。
然后用分治 n t t ntt ntt预处理出 g g g,然后多点求值求 g ′ ( x i ) g'(x_i) g′(xi),最后分治求 f 1 , n f_{1,n} f1,n 即可。
时间复杂度 O ( n log n ) O(nlog n) O(nlogn)。
code:
PS: h h h 数组就是事先处理出的 y i g ′ ( x i ) frac{y_i}{g'(x_i)} g′(xi)yi。
poly Get(int root,int l,int r){
if(l==r)
return poly(1,h[l]);
int mid=(l+r)>>1;
poly L=Get(root<<1,l,mid),R=Get(root<<1|1,mid+1,r);
return L*G[root<<1|1]+R*G[root<<1];
}
下降幂多项式乘法
problem:
给定一个 n n n 次下降幂多项式 A ( x ) A(x) A(x) 和 m m m 次下降幂多项式 B ( x ) B(x) B(x),你要求出一个 ( n + m ) (n+m) (n+m) 次下降幂多项式 F ( x ) F(x) F(x) 满足 F ( x ) = A ( x ) B ( x ) F(x)=A(x)B(x) F(x)=A(x)B(x)。
solution:
首先有一个重要的结论,即:
e x = ∑ i = 0 ∞ x i i ! e^x=sum_{i=0}^inftyfrac{x^i}{i!} ex=i=0∑∞i!xi
这个根据 e x e^x ex 在 0 0 0 处泰勒展开即可得到。
考虑对于 x n ‾ x^{underline n} xn 构建 EGF:
x n ‾ = ∑ i = n ∞ i n ‾ i ! x i = ∑ i = n ∞ 1 ( i − n ) ! x i = ∑ i = n ∞ x i − n ( i − n ) ! x n = x n e x begin{aligned} x^{underline n}&=sum_{i=n}^{infty}frac{i^{underline n}}{i!}x^i\ &=sum_{i=n}^{infty}frac{1}{(i-n)!}x^i\ &=sum_{i=n}^{infty}frac{x^{i-n}}{(i-n)!}x^n\ &=x^ne^x end{aligned} xn=i=n∑∞i!inxi=i=n∑∞(i−n)!1xi=i=n∑∞(i−n)!xi−nxn=xnex
考虑对于 f ( x ) = ∑ i = 0 ∞ a i x i ‾ f(x)=sum_{i=0}^{infty}a_ix^{underline i} f(x)=∑i=0∞aixi 的点值构造 EGF:
g ( x ) = ∑ i = 0 ∞ f ( i ) i ! x i = ∑ i = 0 ∞ x i i ! ∑ j = 0 ∞ a j i j ‾ = ∑ j = 0 ∞ a j ∑ i = 0 ∞ i j ‾ i ! x i = ∑ j = 0 ∞ a j x j e x = e x ∑ i = 0 ∞ a i x i begin{aligned} g(x)&=sum_{i=0}^{infty}frac{f(i)}{i!}x^i\ &=sum_{i=0}^{infty}frac{x^i}{i!}sum_{j=0}^{infty}a_ji^{underline j}\ &=sum_{j=0}^{infty}a_jsum_{i=0}^{infty}frac{i^{underline j}}{i!}x^i\ &=sum_{j=0}^{infty}a_jx^je^x\ &=e^xsum_{i=0}^{infty}a_ix^i end{aligned} g(x)=i=0∑∞i!f(i)xi=i=0∑∞i!xij=0∑∞ajij=j=0∑∞aji=0∑∞i!ijxi=j=0∑∞ajxjex=exi=0∑∞aixi
因此只需要用普通多项式的系数卷个 e x e^x ex 就得到了点值的 EGF。
点值还原原多项式也只需要卷个 e − x e^{-x} e−x。
代码很简单,就是之前的操作,就不放了。
最后
以上就是小巧帆布鞋为你收集整理的多项式各种操作的全部内容,希望文章能够帮你解决多项式各种操作所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复