一.插值的定义.
插值:给定若干个点 ( x i , y i ) (x_i,y_i) (xi,yi),确定一条函数曲线 f ( x ) f(x) f(x)满足对于所有 i i i,有 f ( x i ) = y i f(x_i)=y_i f(xi)=yi的过程称为插值.
多项式插值:给定 n + 1 n+1 n+1个 x i x_i xi两两不同的点 ( x i , y i ) (x_i,y_i) (xi,yi),确定一个多项式 f ( x ) = ∑ i = 0 n a i x i f(x)=\sum_{i=0}^{n}a_ix^{i} f(x)=∑i=0naixi满足对于所有 i i i,有 f ( x i ) = y i f(x_i)=y_i f(xi)=yi的过程称为插值.
方便起见,接下来若没有说明,则下文所说的所有插值均指多项式插值.
二.朴素插值方法.
根据插值的定义,很容易列出如下方程组:
{
a
0
+
a
1
x
0
+
a
2
x
0
2
+
⋯
+
a
n
x
0
n
=
y
0
a
0
+
a
1
x
1
+
a
2
x
1
2
+
⋯
+
a
n
x
1
n
=
y
1
⋮
a
0
+
a
1
x
n
+
a
2
x
n
2
+
⋯
+
a
n
x
n
n
=
y
n
\left\{\begin{matrix} a_0+a_1x_0+a_2x_0^2+\cdots+a_nx_0^n=y_0\\ a_0+a_1x_1+a_2x_1^2+\cdots+a_nx_1^n=y_1\\ \vdots\\ a_0+a_1x_n+a_2x_n^2+\cdots+a_nx_n^n=y_n \end{matrix}\right.
⎩⎪⎪⎪⎨⎪⎪⎪⎧a0+a1x0+a2x02+⋯+anx0n=y0a0+a1x1+a2x12+⋯+anx1n=y1⋮a0+a1xn+a2xn2+⋯+anxnn=yn
接下来只需要高斯消元,就可以在
O
(
n
3
)
O(n^3)
O(n3)的时间复杂度内求出这个多项式了.
三.拉格朗日插值法.
显然, O ( n 3 ) O(n^3) O(n3)的时间复杂度并不令人满意,考虑有没有其他更加优秀的算法.
拉格朗日插值法的思路是构造
n
+
1
n+1
n+1个基础多项式
l
i
(
x
)
l_i(x)
li(x)满足:
l
i
(
x
i
)
=
1
j
≠
i
⇒
l
i
(
x
j
)
=
0
l_i(x_i)=1\\ j\neq i\Rightarrow l_i(x_j)=0
li(xi)=1j=i⇒li(xj)=0
然后拉格朗日构造出了这样的基础多项式:
l
i
(
x
)
=
∏
j
≠
i
x
−
x
j
x
i
−
x
j
l_i(x)=\prod_{j\neq i}\frac{x-x_j}{x_i-x_j}
li(x)=j=i∏xi−xjx−xj
有了这
n
+
1
n+1
n+1个基础多项式,我们就可以通过它们的线性组合得到
f
(
x
)
f(x)
f(x):
f
(
x
)
=
∑
i
=
0
n
y
i
l
i
(
x
)
=
∑
i
=
0
n
y
i
∏
j
≠
i
x
−
x
j
x
i
−
x
j
f(x)=\sum_{i=0}^{n}y_il_i(x)=\sum_{i=0}^{n}y_i\prod_{j\neq i}\frac{x-x_j}{x_i-x_j}
f(x)=i=0∑nyili(x)=i=0∑nyij=i∏xi−xjx−xj
也就是说若我们直接将多项式用
n
+
1
n+1
n+1个点存下来,就可以做到
O
(
n
2
)
O(n^2)
O(n2)计算带入某个
x
x
x的值.
四.求出多项式的系数表示.
乍一看,如果要计算出这个多项式的系数表示,怎么着复杂度也是 O ( n 3 ) O(n^3) O(n3)的…
其实不然,我们来转化一下:
f
(
x
)
=
∑
i
=
0
n
y
i
∏
j
≠
i
x
−
x
j
x
i
−
x
j
=
∑
i
=
0
n
y
i
∏
j
=
0
n
(
x
−
x
j
)
x
−
x
i
1
∏
j
≠
i
(
x
i
−
x
j
)
f(x)=\sum_{i=0}^{n}y_i\prod_{j\neq i}\frac{x-x_j}{x_i-x_j}\\ =\sum_{i=0}^{n}y_i\frac{\prod_{j=0}^{n}(x-x_j)}{x-x_i}\frac{1}{\prod_{j\neq i}(x_i-x_j)}
f(x)=i=0∑nyij=i∏xi−xjx−xj=i=0∑nyix−xi∏j=0n(x−xj)∏j=i(xi−xj)1
令
t
i
=
y
i
∏
j
≠
i
(
x
i
−
x
j
)
t_i=\frac{y_i}{\prod_{j\neq i}(x_i-x_j)}
ti=∏j=i(xi−xj)yi,容易发现
t
i
t_i
ti可以暴力计算,那么剩下的式子就是:
f
(
x
)
=
∑
i
=
0
n
t
i
∏
j
=
0
n
(
x
−
x
j
)
x
−
x
i
f(x)=\sum_{i=0}^{n}t_i\frac{\prod_{j=0}^{n}(x-x_j)}{x-x_i}
f(x)=i=0∑ntix−xi∏j=0n(x−xj)
令
g
(
x
)
=
∏
i
=
0
n
(
x
−
x
i
)
g(x)=\prod_{i=0}^{n}(x-x_i)
g(x)=∏i=0n(x−xi),容易发现
g
(
x
)
g(x)
g(x)也可以暴力算,式子变为:
f
(
x
)
=
∑
i
=
0
n
t
i
g
(
x
)
x
−
x
i
f(x)=\sum_{i=0}^{n}t_i\frac{g(x)}{x-x_i}
f(x)=i=0∑ntix−xig(x)
接下来的问题就是 O ( n ) O(n) O(n)计算 g ( x ) x − x i \frac{g(x)}{x-x_i} x−xig(x),这可以用背包方案数的技巧做到.
时间复杂度
O
(
n
2
)
O(n^2)
O(n2).
五.利用拉格朗日插值法计算自然数幂和.
首先我们需要推一下自然数幂和的式子.记:
S
k
(
n
)
=
∑
i
=
1
n
i
k
S_{k}(n)=\sum_{i=1}^{n}i^{k}
Sk(n)=i=1∑nik
那么有:
S
k
(
n
)
=
S
k
(
n
+
1
)
−
(
n
+
1
)
k
=
∑
i
=
1
n
(
i
+
1
)
k
−
(
n
+
1
)
k
+
1
=
∑
i
=
1
n
∑
j
=
0
k
(
k
j
)
i
j
−
(
n
+
1
)
k
+
1
=
∑
i
=
0
k
(
k
i
)
∑
j
=
1
n
j
i
−
(
n
+
1
)
k
+
1
=
∑
i
=
0
k
(
k
i
)
S
i
(
n
)
−
(
n
+
1
)
k
+
1
S_k(n)=S_k(n+1)-(n+1)^{k}\\ =\sum_{i=1}^{n}(i+1)^{k}-(n+1)^{k}+1\\ =\sum_{i=1}^{n}\sum_{j=0}^{k}\binom{k}{j}i^{j}-(n+1)^{k}+1\\ =\sum_{i=0}^{k}\binom{k}{i}\sum_{j=1}^{n}j^{i}-(n+1)^{k}+1\\ =\sum_{i=0}^{k}\binom{k}{i}S_{i}(n)-(n+1)^{k}+1
Sk(n)=Sk(n+1)−(n+1)k=i=1∑n(i+1)k−(n+1)k+1=i=1∑nj=0∑k(jk)ij−(n+1)k+1=i=0∑k(ik)j=1∑nji−(n+1)k+1=i=0∑k(ik)Si(n)−(n+1)k+1
推到这一步,我们来尝试一下推出
S
k
−
1
(
n
)
S_{k-1}(n)
Sk−1(n):
S
k
−
1
(
n
)
=
1
k
(
(
n
+
1
)
k
−
1
−
∑
i
=
0
k
−
2
(
k
i
)
S
i
(
n
)
)
S_{k-1}(n)=\frac{1}{k}\left((n+1)^{k}-1-\sum_{i=0}^{k-2}\binom{k}{i}S_i(n)\right)
Sk−1(n)=k1((n+1)k−1−i=0∑k−2(ik)Si(n))
也就是:
S
k
(
n
)
=
1
k
+
1
(
(
n
+
1
)
k
+
1
−
1
−
∑
i
=
0
k
−
1
(
k
+
1
i
)
S
i
(
n
)
)
S_{k}(n)=\frac{1}{k+1}\left((n+1)^{k+1}-1-\sum_{i=0}^{k-1}\binom{k+1}{i}S_{i}(n)\right)
Sk(n)=k+11((n+1)k+1−1−i=0∑k−1(ik+1)Si(n))
经过一波操作之后,我们确定了自然数幂和的式子,但是直接计算是 O ( k 2 ) O(k^2) O(k2)的,并不够优秀.
经过观察之后,我们发现这个式子必然是关于 n n n的 k + 1 k+1 k+1次多项式,那么接下来就是计算点和拉格朗日插值了.
计算点非常容易,对于所有 i ∈ [ 0 , k + 1 ] i\in [0,k+1] i∈[0,k+1],只需要计算出 i k i^{k} ik然后前缀和一下就是 S k ( i ) S_k(i) Sk(i)了,这一部分的时间复杂度为 O ( k log k ) O(k\log k) O(klogk).
然后是拉格朗日插值,然而是 O ( k 2 ) O(k^2) O(k2)的,复杂度并没有变…
但是这不是大问题,我们观察所取的点,发现是连续的 k + 2 k+2 k+2个点,这会有什么用呢?
代入拉格朗日插值公式:
f
(
n
)
=
∑
i
=
0
k
+
1
S
k
(
i
)
∏
j
≠
i
n
−
j
i
−
j
=
∑
i
=
0
k
+
1
S
k
(
i
)
1
i
!
(
−
1
)
k
+
1
−
i
(
k
+
1
−
i
)
!
∏
j
≠
i
(
n
−
j
)
f(n)=\sum_{i=0}^{k+1}S_k(i)\prod_{j\neq i}\frac{n-j}{i-j}\\ =\sum_{i=0}^{k+1}S_k(i)\frac{1}{i!(-1)^{k+1-i}(k+1-i)!}\prod_{j\neq i}(n-j)
f(n)=i=0∑k+1Sk(i)j=i∏i−jn−j=i=0∑k+1Sk(i)i!(−1)k+1−i(k+1−i)!1j=i∏(n−j)
对于最后一个连乘式,我们令:
P
(
i
)
=
∏
j
=
0
i
(
n
−
j
)
S
(
i
)
=
∏
j
=
i
k
+
1
(
n
−
j
)
P(i)=\prod_{j=0}^{i}(n-j)\\ S(i)=\prod_{j=i}^{k+1}(n-j)
P(i)=j=0∏i(n−j)S(i)=j=i∏k+1(n−j)
那么有:
f
(
n
)
=
∑
i
=
0
k
+
1
S
k
(
i
)
P
(
i
−
1
)
∗
S
(
i
+
1
)
i
!
(
−
1
)
k
+
1
−
i
(
k
+
1
−
i
)
!
f(n)=\sum_{i=0}^{k+1}S_k(i)\frac{P(i-1)*S(i+1)}{i!(-1)^{k+1-i}(k+1-i)!}
f(n)=i=0∑k+1Sk(i)i!(−1)k+1−i(k+1−i)!P(i−1)∗S(i+1)
这就可以做到 O ( k ) O(k) O(k)拉格朗日插值了.
总时间复杂度即为 O ( k log k ) O(k\log k) O(klogk).通过一个线性筛 i k i^{k} ik的操作,可以做到 O ( k ) O(k) O(k).