浅谈拉格朗日插值

1. 多项式插值定理

我们知道,两点可以确定一条直线(一次多项式),而三点可以确定一条二次函数,四点可以确定一个三次函数 ......

这不由得让我们产生思考——给定 n+1 个点,是否有一个唯一的 n 次多项式过这所有点呢?答案是肯定的,这个定理被称作 多项式插值定理,证明见 * 一节 .

注意做题时必须确定答案是多项式才能插值,比如对非常平稳的一组点做插值时:

,,,,,,,,,,[表情]

2. 插值方法

由于多项式插值定理的存在,我们下面研究一个问题:给定 n+1 个点 (x0,y0),(x1,y1),,(xn,yn),求一个多项式 f(x) 使得 f(xi)=yi) .

0. 暴力(Get 0 Points)插值

和多项式插值定理的证明差不多,高斯消元解方程组即可,时间复杂度 O(n3) .

当然也可以用 Cramer 法则求出解的表达式然后解行列式,也是 O(n3) 的,但是常数会高一些

1. 拉格朗日(Lagrange)插值

1. 朴素做法

考虑构造 n+1 个多项式 gi(x),使得 gi(xi)=yi,且对于任意 ijgi(xj)=0,然后 i=0ngi(x) 即是所求多项式 .

构造这个 gi,可以令 gi(x)=yii(x),这样 i(x) 只取 {0,1},那么自然满足条件 .

i(x)

i(x)=ijxxjxixj

即可,当 x=xi 时,每项都是 xixjxixj=1,当 xxi 时,一定有一项使得分子为 0 .

所以我们就得到了拉格朗日插值公式:

Ln(x)=i=0nyiijxxjxixj

上面设的 i(x) 称做拉格朗日基本多项式(插值基函数),Ln(x) 叫做拉格朗日插值多项式 .

下面给出模板题 洛谷 P4781 的代码:

ll ans=0,x[N],y[N];
int n,k;
ll qpow(ll a,ll n)
{
	ll ans=1;
	while (n)
	{
		if (n&1) ans=ans*a%MOD;
		a=a*a%MOD; n>>=1;
	} return ans%MOD;
}
int main()
{
	scanf("%d%d",&n,&k);
	for (int i=1;i<=n;i++) scanf("%lld%lld",x+i,y+i);
	for (int i=1;i<=n;i++)
	{
		ll P=1,Q=1;
		for (int j=1;j<=n;j++)
			if (i!=j){P=P*(k-x[j])%MOD; Q=Q*(x[i]-x[j])%MOD;}
		ans=(ans+y[i]*P%MOD*qpow(Q,MOD-2)%MOD)%MOD;
	} printf("%lld",(ans%MOD+MOD)%MOD);
	return 0;
}

这里因为是模 998244353 意义下的,所以用了逆元 .

其截断误差由如下定理得出

f(x)Cn+1[a,b]L(x)f 在区间 [a,b]n+1 个不同点 x0,x1,,xn 上的次数不超过 n 的插值多项式,则对每个 x[a,b] 都存在 ξx[a,b] 满足:

f(x)L(x)=1(n+1)!f(n+1)(ξx)i=0n(xxi)

证明见 * 一节 .

注意到利用定理估计截断误差实际上很困难,一是因为上式要计算 f(x) 高阶导数,二是 ξx 的位置不确定 .

若有 n+2 组数据,前 n+1 个做一次插值,后 n+1 个做一次插值,然后相减化一下式子即可获得比较实用的公式 .

2. 当 xi 连续时的更优做法

不妨加上 xi=i,则有

Ln(x)=i=0nyiijxjij

维护 kj 的前缀积,后缀积和阶乘即可 .

3. 重心拉格朗日插值

注意到每次新加入一个点的时候要重新插值,如果要多次增加点,拉格朗日插值就 gg 了 .

先看一下前面的式子

Ln(x)=i=0nyiijxxjxixj

g=i=0n(kxi)

Ln(x)=gi=0nijyi(xxi)(xixj)

发现只有 xxi 是变化的,则令

wi=yixixj

从而

Ln(x)=gi=0nijwixxi

每次加点时 O(n) 算出 wi 即可求出新的 Ln(x) .

3. 快速插值

1. O(nlog3n) 插值

2. O(n2log2n) 插值

3. O(nlog2n) 插值

4. 一些例题

1. 自然数 k 次方和

给定 n,k,求 i=1nik109+7 取模的结果 .

先对 k 一定的序列差分,然后发现是 k 次的,所以原式是 k+1 次的,取 1k+2 跑拉格朗日插值即可 .

typedef long long ll;
const int N=2e6+5,MOD=1e9+7;
ll pre[N],suf[N],fac[N],n,k;
ll qpow(ll a,ll n)
{
	ll ans=1;
    while (n)
    {
        if (n&1) ans=ans*a%MOD;
        a=a*a%MOD; n>>=1;
    } return ans%MOD;
}
int main()
{
	scanf("%lld%lld",&n,&k); pre[0]=suf[k+3]=fac[0]=1;
	for (int i=1;i<=k+2;i++) pre[i]=pre[i-1]*(n-i)%MOD;
	for (int i=k+2;i>=1;i--) suf[i]=suf[i+1]*(n-i)%MOD;
	for (int i=1;i<=k+2;i++) fac[i]=fac[i-1]*i%MOD;
	ll tmp=0,ans=0;
	for (int i=1;i<=k+2;i++)
	{
		tmp=(tmp+qpow(i,k))%MOD;
		ll P=pre[i-1]*suf[i+1]%MOD,Q=fac[i-1]*((k-i)&1?-1:1)*fac[k+2-i]%MOD;
		ans=(ans+tmp*P%MOD*qpow(Q,MOD-2)%MOD)%MOD;
	} printf("%lld\n",(ans+MOD)%MOD);
	return 0;
}

*. 有关定理的证明

1. 多项式插值定理

x0,x1,,xn 是不同实数,则对任意实数 y0,y1,,yn 存在唯一的次数最多是 n 次的多项式 f(x) 满足 f(xi)=yi .

Proof:

f(x)=anxn+an1xn1++a1x+a0,则有

{anx0n+an1x0n1++a1x0+a0anx1n+an1x1n1++a1x1+a0anx2n+an1x2n1++a1x2+a0anxn1n+an1xn1n1++a1xn1+a0anxnn+an1xnn1++a1xn+a0

a0,a1,,an 做变量,则其系数行列式

|1x1x1n1x2x2n1xnxnn|=ij(xixj)

这一步是由于其系数行列式为转置的范德蒙德(Vandermonde)行列式。又由于 Cramer 法则,因其系数行列式不等于 0,从而方程有唯一解,即多项式存在且唯一 .

2. 多项式插值误差定理

f(x)Cn+1[a,b]L(x)f 在区间 [a,b]n+1 个不同点 x0,x1,,xn 上的次数不超过 n 的插值多项式,则对每个 x[a,b] 都存在 ξx[a,b] 满足:

f(x)L(x)=1(n+1)!f(n+1)(ξx)i=0n(xxi)

Proof:

x{x0,x1,,xn},上式显然成立 .
否则令 φ(t)=f(t)L(t)λω,其中 ω=i=0n(txi)λ=f(x)L(x)ω(x)
显然 φ(t) 至少有 x,x0,x1,,xnn+2 个不同的根,由罗尔定理,φ(n+1) 至少有一个零点 ξx,形式化的,有

φ(n+1)(ξx)=f(n+1)(ξx)λ(n+1)!=0

从而,有

f(x)L(x)=1(n+1)!f(n+1)(ξx)i=0n(xxi)

posted @   yspm  阅读(540)  评论(1编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
😅​
点击右上角即可分享
微信分享提示