拉格朗日插值多项式

其实一直想写一写知识总结,但是长时间处于一种摆烂的状态,最近正好复习了一些比较有趣的知识,所以就拿出来写一写吧。

下文大致分为两个部分:
第一部分介绍拉格朗日插值法的简单应用,第二部分则时拉格朗日公式的推导。

书籍中科学的证明和严谨的逻辑固然重要,但绝大多数人很难通过阅读那些虽严谨但枯燥的公式便入门一个知识。我认为数学并不只是天才的游戏,更应该让我们这些普通人领略数学之美,所以在公式的推导过程中,我将带领着感兴趣的朋友一步步前进与思考,慢慢走到拉格朗日插值公式的面前。

\[f(x) = \sum_{i=1}^{n} f\left(x_{i}\right) \prod_{j \neq i} \frac{x-x_{j}}{x_{i}-x_{j}}\tag{lagrange} \]

拉格朗日插值多项式的应用

如果有\(n\) 个二维坐标点\(\left(x_{i}, y_{i}\right)\)(任意两个点横坐标不相等)可以确定一个\(n-1\)次多项式函数 \(y=f(x)\)
拉格朗日插值法可以根据这\(n\)个点求出这个多项式\(f(x)\)。当然,实际应用中通常求出横坐标为\(a\)的点在该(\(n\)个点确定的)多项式函数上对应的纵坐标的值。

例题如下:
给定一个整数\(n\),和一个整数\(k\),接着给出\(n\)个点的坐标,此时需要用这\(n\)个点确定一个多项式\(y=f(x)\),并求出\(f(k)mod998244353\)的值。(洛谷模板题)

数据如下:

3 100
1 4
2 9
3 16

乍一看可能没有什么思路,那么我们来考虑一个简单的二次函数问题吧:
已知\(3\)个点\((x_1,1)\),\((x_2,0)\)\((x_3,0)\),求\(f(x)\)

\(f_1(x)\)表示经过点\((x_1,1)\),\((x_2,0)\)\((x_3,0)\)的二次函数
\(f_2(x)\)表示经过点\((x_1,0)\),\((x_2,1)\)\((x_3,0)\)的二次函数
\(f_3(x)\)表示经过点\((x_1,0)\),\((x_2,0)\)\((x_3,1)\)的二次函数

那么很显然有\(f(x)=y_{1} \cdot f_{1}(x)+y_{2} \cdot f_{2}(x)+y_{3} \cdot f_{3}(x)\)(可以思考一下为什么?)

接着我们要求其中的子函数,以\(f_1(x)\)为例:
从我们的规定中可以发现,\(f_1(x)=0\)的根其实就是\(x_2\)\(x_3\),那么我们可以设整数\(k\),那么就存在:
\(f_{1}(x)=k\left(x-x_{2}\right)\left(x-x_{3}\right)\),再将点\((x_1,1)\)代入,即可得到一个全新的表达式:

\[f_{1}(x)=\frac{\left(x-x_{2}\right)\left(x-x_{3}\right)}{\left(x_{1}-x_{2}\right)\left(x_{1}-x_{3}\right)} \]

那么我们便可以用给出的点求出\(f(x)\)即可。(\(f(x)\)是一个\(n-1\)次多项式)
细心的朋友可以发现,当这个式子整理一下,便是开头给出的\(lagrange\)公式的形式。

那么对于任意高次函数求便可以使用拉格朗日求出该多项式,那么对于例题,我们便可以求解出\(f(x)\)\(k\)代入即可。

代码如下:

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N=3e3,M=998244353;

int n,k;
int x[N],y[N];

int inv(int a,int b)
{
	int res=1;
	while(b)
	{
		if(b&1) res=(LL)res*a%M;
		a=(LL)a*a%M;
		b>>=1;
	}
	return res;
}

signed main()
{
	ios::sync_with_stdio(0);cin.tie(0);
	cin>>n>>k;
	
	for(int i=1;i<=n;i++) cin>>x[i]>>y[i];
	
	int res=0;
	for(int i=1;i<=n;i++)
	{
		LL a=y[i]%M;
		LL b=1;
		for(int j=1;j<=n;j++)
		{
			if(i==j) continue;
			a=(a*(LL)(k-x[j]))%M;
			b=(b*(LL)(x[i]-x[j]))%M;
		}
		res=(res+a*inv(b,M-2)%M)%M;
	}
	cout<<(res%M+M)%M;
}

拉格朗日插值公式推导

拉格朗日插值公式(外文名Lagrange interpolation formula)指的是在节点上给出节点基函数,然后做基函数的线性组合,组合系数为节点函数值的一种插值多项式。————抄自百度百科

在了解了简单的拉格朗日公式的用法后,下面将从最简单的余数开始,一步步带领阅读到这里的朋友,一步步前进,最后得到拉格朗日插值公式。

第一步(认识余数)

余数相信大家都不陌生,当两个数不能整除时,就产生了余数,如下所示:

\[5 \div 2=2 \cdots 1 \]

\[3 \div 2=1 \cdots 1 \]

第二步(了解同余(中国剩余定理解线性同余方程组))

对于上面那两个公式,我们可以发现,在对2取余的情况下,5的余数与3的余数相同,都为1,所以我们可以写出两个同余式,如下:

\[5 \equiv 1(\bmod 2) \]

\[3 \equiv 1(\bmod 2) \]

观察一下,可以发现,5和3在对2取余的情况下也是相同的,所以便可以得到下面这个同余式:

\[5 \equiv 3(\bmod 2) \]

下面需要掌握一些同余式的基本性质:
如果\(a \equiv b(\bmod m)\),并且\(c \equiv d(\bmod m)\)那么就可以得到:

\[a + c \equiv b + d(\bmod m)\tag1 \]

如果\(a \equiv b(\bmod m)\),并且\(c \equiv d(\bmod m)\)那么就可以得到:

\[a - c \equiv b - d(\bmod m)\tag2 \]

如果\(a \equiv b(\bmod m)\),并且\(c \equiv d(\bmod m)\)那么就可以得到:

\[ac \equiv bd(\bmod m)\tag3 \]

但是对于除法我们并不能采用上述的形式。在这里我们引入一个新的概念:逆元

如果存在\(ab \equiv 1(\bmod m)\),那么就定义\(a^{-1} \equiv b(\bmod m)\),此时b就是a在模m意义下的乘法逆元。

对于b的求解方法可以使用扩展欧几里得算法,这里不再赘述,只需要找到一个整数b即可。

那么除法就可以用乘法来代替了:

如果\(a \equiv b(\bmod m)\),并且\(c \equiv d(\bmod m)\)那么就可以得到:(值得注意的是此处的\(k^{-1}\)表达的是数子k的乘法逆元!)

\[ac^{-1} \equiv bd^{-1}(\bmod m)\tag4 \]

到这里可以思考一下,对于上面的式子可以推导一下,便于掌握简单的同余式。

第三步(求解线性同余方程组)

首先我们看一个问题,有以下\(n\)个式子(\(a\geq 1\),\(m \geq 0\)):

\[\left\{\begin{array}{} x \equiv a_{1}(\bmod m_{1})\\ x \equiv a_{2}(\bmod m_{2})\\ x \equiv a_{3}(\bmod m_{3})\\ \vdots\\ x \equiv a_{n}(\bmod m_{n}) \end{array}\right.\tag{5}\]

我们要做的就是找到一个整数\(x\)使得上述\(n\)个式子均成立。

第一次遇到这种问题可能会感觉无从下手,那么我们先来看一组神奇的式子:

\[\left\{\begin{array}{l} 6 \equiv 0(\bmod 3) \\ 6 \equiv 1(\bmod 5) \end{array}\right.\]

\[\left\{\begin{array}{l} 10 \equiv 1(\bmod 3) \\ 10 \equiv 0(\bmod 5) \end{array}\right.\]

如果让我们在上述式子已知的情况下如果求一个除以5余1,除以3余1的数该怎么求呢?很显然,在之前我们已经了解了同余式加法的性质,那么只需要将上面两组式子加起来就可以得到结果:

\[\left\{\begin{array}{l} 16 \equiv 1(\bmod 3) \\ 16 \equiv 1(\bmod 5) \end{array}\right.\]

那么如果是求一个除以5余3,除以3余2的数呢?很明显,将第一组式子\(*3\)将第二组式子\(*3\)即可:

\[\left\{\begin{array}{l} 38 \equiv 2(\bmod 3) \\ 38 \equiv 3(\bmod 5) \end{array}\right.\]

那么为什么会这样呢,思考一下不难发现,因为第一组相当于除数5的一组基向量,而第二组就相当于除数3的一组基向量。

那么我们可以思考一下,如何在已知多个同余方程的情况下,求出基向量呢?

举个简单的例子,有下面三个同余方程:

\[\left\{\begin{array}{} 5 \equiv 2(\bmod 3) \\ 9 \equiv 4(\bmod 5) \\ 8 \equiv 1(\bmod 7) \end{array}\right.\]

那么我们来思考一下,如何求模数3的基向量。
首先这个数字一定对5,7能够整除,那么直接把他们相乘即可。
那么得到一个全新的式子\(35*x \equiv 1(\bmod 3)\)
相信仔细阅读过乘法逆元的朋友可以惊喜的发现,我们要找的\(x\)就是\(35\)在模\(3\)意义下的乘法逆元。那么\(x\)可以取得最小值便是\(2\)
故在上面的式子中模数3的基向量为70,同理便可以得到其余两个模数的基向量。

在充分思考了上面的求解过程后,我们把思路稍加整理,便可以得到适用于式\((5)\)通用基向量公式:

\[\left\{\begin{array}{} M_{i}=\frac{M}{m_{i}}, i=1,2, \cdots, n \tag6 \\ \vec{e}_{i}=M_{i}\left[M_{i}\right]^{-1} \bmod m_{i} \end{array}\right.\]

简单介绍一下上述两式,第一个可以看出其实就是除了当前要求的基向量以外,其他所有模数的积,而第二个式子则时这个积乘以它的乘法逆元。结果便是当前所求模数的基向量。

求解出所有的基向量后,便可以计算\((5)\)式的答案了,只需要将对应的\(a\)乘上它所对应的基向量\(e_{i}\)即可。(需要注意最后取模数时是所有模数的乘积,也就是\(M\))写成公式如下:

\[\left\{\begin{array}{} M=\prod_{i=1}^{n} m_{i} \\ x \equiv \sum_{i=1}^{n} a_{i} \vec{e}_{i}(\bmod M) \end{array}\right.\tag7\]

如果你看到了这里,那么恭喜你成功学会了如何使用中国剩余定理解决线性同余方程组了__

第三步(将前面所讲的同余定理推广到整式)

那么我们可以类比式\((1)\)\((2)\)\((3)\)得到以下公式:

\[\left\{\begin{array}{} a(x)+c(x) \equiv b(x)+d(x)(\bmod m(x)) \\ a(x)-c(x) \equiv b(x)-d(x)(\bmod m(x)) \\ a(x)c(x) \equiv b(x)d(x)(\bmod m(x)) \\ ac^{-1} \equiv bd^{-1}(\bmod m) \end{array}\right.\]

接下来我们考虑一个一次式:\(x \div(x-a)=1 \cdots \cdots a\)

可以得出同余式:\(x \equiv a(\bmod x-a)\)
所以可以得出同余式子:\(x^n \equiv a^n(\bmod x-a)\)

所以我们可以推广得到对于任意函数\(f(x)\)和一个整数\(a\)存在如下关系:$$f(x) \equiv f(a)(\bmod x-a)$$
为了方便可以先将\(f(x)\)逆元表达式写成如下式子:

\[f^{-1}(x) \equiv \frac{1}{f(a)}(\bmod x-a) \]

第四步(考虑整式的中国剩余定理)

我们可以对式子\((5)(6)(7)\)进行替换便可以得到如下公式:

\[\left\{\begin{array}{} f(x)\equiv a_{1}(x)(\bmod m_{1}(x))\\ f(x) \equiv a_{2}(x)(\bmod m_{2}(x))\\ f(x) \equiv a_{3}(x)(\bmod m_{3}(x))\\ \vdots\\ f(x) \equiv a_{n}(x)(\bmod m_{n}(x)) \end{array}\right.\tag{8}\]

\[\left\{\begin{array}{} M_{i}(x)=\frac{M(x)}{m_{i}(x)}, i=1,2, \cdots, n \\ \vec{e}_{i}(x)=M_{i}(x)\left[M_{i}(x)\right]^{-1} \bmod m_{i}(x) \end{array}\right.\tag9\]

\[\left\{\begin{array}{} M(x)=\prod_{i=1}^{n} m_{i}(x) \\ f(x) \equiv \sum_{i=1}^{n} a_{i}(x) \vec{e}_{i}(x)(\bmod M(x)) \end{array}\right.\tag{10}\]

我们发现上述情况可以套用第二步中所介绍的方法进行解决。

接下来我们依然考虑所有的\(f(x),a(x),m(x)\)均是一次式的情况,那么就存在如下方程组:

\[\left\{\begin{array}{} f(x)\equiv a_{1}(x)(\bmod x-x_1)\\ f(x) \equiv a_{2}(x)(\bmod x-x_2\\ f(x) \equiv a_{3}(x)(\bmod x-x_3)\\ \vdots\\ f(x) \equiv a_{n}(x)(\bmod x-x_n) \end{array}\right.\]

首先由于之前得出在一次式情况下存在\(f(x) \equiv f(a)(\bmod x-a)\)那么可以得到:

\[\left\{\begin{array}{} f(x)\equiv f(x_1)(\bmod x-x_1)\\ f(x) \equiv f(x_2)(\bmod x-x_2\\ f(x) \equiv f(x_3)(\bmod x-x_3)\\ \vdots\\ f(x) \equiv f(x_n)(\bmod x-x_n) \end{array}\right.\]

那么我们遍可以修改\((10)\)式:

\[\left\{\begin{array}{} M(x)=\prod_{i=1}^{n} m_{i}(x) \\ f(x) \equiv \sum_{i=1}^{n} f(x_i) \vec{e}_{i}(x)(\bmod M(x)) \end{array}\right.\tag{10}\]

最后让我们来观察一下\((9)\)式:

\[M_{i}(x)=\frac{\left(x-x_{1}\right) \cdots\left(x-x_{n}\right)}{(x-x_i)} \]

同样由于在一次整式的情况下我们得出:\(f^{-1}(x) \equiv \frac{1}{f(a)}(\bmod x-a)\)

所以可以得出:

\[\left[M_{i}(x)\right]_{\bmod x-x_{i}}^{-1} \equiv \frac{1}{M_{i}\left(x_{i}\right)}\left(\bmod x-x_{i}\right) \]

那么\((9)\)式便可以更改为:

\[\left\{\begin{array}{} M_{i}(x)=\frac{\left(x-x_{1}\right) \cdots\left(x-x_{n}\right)}{(x-x_i)} \\ \vec{e}_{i}(x)=M_{i}(x)\left[M_{i}(x)\right]^{-1} \bmod m_{i}(x)=\prod_{j \neq 1} \frac{x-x_{j}}{x_{1}-x_{j}} \end{array}\right.\]

此时我们将基向量的表达式带入到\((10)\)式中便可以得到拉格朗日插值公式的雏形:

\[f(x) \equiv \sum_{i=1}^{n} f\left(x_{i}\right) \prod_{j \neq i} \frac{x-x_{j}}{x_{i}-x_{j}}(\bmod M(x)) \]

\(M(x)\) 的次数大于\(\sum_{i=1}^{n} f\left(x_{i}\right) \prod_{j \neq i} \frac{x-x_{j}}{x_{i}-x_{j}}\)求和后的次数时,存在等式(拉格朗日插值公式):

\[f(x) = \sum_{i=1}^{n} f\left(x_{i}\right) \prod_{j \neq i} \frac{x-x_{j}}{x_{i}-x_{j}} \]

现在大家看到的就是拉格朗日插值多项式公式的表达式了,很高兴和大家一起推导到这里。
文章到这里就结束了,整体思路来自B站up主乐正垂星的视频讲解,也有大量我思考的过程,衷心感谢看到这里的朋友,也希望这篇文章能够对你有所帮助^ ^。

posted @ 2022-06-11 14:31  冷-离  阅读(632)  评论(0)    收藏  举报