Learning:拉格朗日插值

问题: 已知点 ( x 0 , y 0 ) , ( x 1 , y 1 ) , . . . , ( x n , y n ) (x_0,y_0),(x_1,y_1),...,(x_n,y_n) (x0,y0),(x1,y1),...,(xn,yn),求一个经过这n个点的n次多项式。
一种做法是设出这个多项式,然后将n个点带入得到n个方程,然后用高斯消元在 O ( n 3 ) O(n^3) O(n3)的时间求出。
但是复杂度太高了,所以就有了拉格朗日插值这种优秀算法。
注意,部分定义不保证严谨性,但是不影响拉格朗日插值法的应用

l j ( x ) l_j(x) lj(x) j j j的拉格朗日基本多项式,表示一个在 x = x j x=x_j x=xj处等于1且在 x = x i ( i ≠ j ) x=x_i(i\not=j) x=xi(i=j)处等于0的多项式。
这个多项式很好构造,即 ∏ i = 0 , i ≠ j n x − x i x j − x i \prod_{i=0,i\not=j}^n\frac{x-x_i}{x_j-x_i} i=0,i=jnxjxixxi
那么要满足所有点,只需将所有拉格朗日基本多项式乘上 y j y_j yj再加起来就是最终的n次多项式。
f ( x ) = ∑ j = 0 n l j ( x ) y i f(x)=\sum_{j=0}^nl_j(x)y_i f(x)=j=0nlj(x)yi
但是直接做好像还是 n 3 n^3 n3
考虑进行优化(叫重心拉格朗日插值法)
我们设 w j = ∏ i = 0 , i ≠ j n 1 x j − x i , g ( x ) = ∏ i = 0 n + 1 x − x i w_j=\prod_{i=0,i\not=j}^n\frac{1}{x_j-x_i},g(x)=\prod_{i=0}^{n+1}x-x_i wj=i=0,i=jnxjxi1,g(x)=i=0n+1xxi
我们先在插值前预处理出 g ( x ) g(x) g(x),然后在枚举 j j j时每次 O ( n ) O(n) O(n)计算 w w w,即 l j ( x ) l_j(x) lj(x)的分母部分,然后 O ( n ) O(n) O(n) g ( x ) g(x) g(x)暴力除以 x − x j x-x_j xxj得到 l j ( x ) l_j(x) lj(x)的分子部分,即可在 O ( n ) O(n) O(n)的时间内求出 l j ( x ) l_j(x) lj(x),加上枚举j的复杂度,总复杂度为 O ( n 2 ) O(n^2) O(n2)
注意如果是单点求值,则只需要直接替换 x x x即可,时间复杂度仍为 O ( n 2 ) O(n^2) O(n2)
代码:

void lagrange(int *f,int n){
	memset(l,0,sizeof(l));
	l[0]=1;
	f[0]=0;
	for(int i=0;i<=n;i++){
		f[i]=0;
		for(int j=i+1;j>0;j--)
			l[j]=Minus(l[j-1],1ll*l[j]*x[i]%mod);
		l[0]=Minus(0,1ll*l[0]*x[i]%mod);
	}//求g
	for(int i=0;i<=n;i++){
		int w=y[i];
		for(int j=0;j<=n;j++)
			if(i!=j)
				w=1ll*w*inv[x[j]>x[i]][abs(x[j]-x[i])]%mod;//inv[0/1][j]分别表示1~n和mod-n~mod-1的逆元,如在实数范围则可直接取倒数
		t[n]=1;
		f[n]=(f[n]+1ll*t[n]*w)%mod;
		for(int j=n-1;j>=0;j--){
			t[j]=(l[j+1]+1ll*t[j+1]*x[i])%mod;//暴力除法
			f[j]=(f[j]+1ll*t[j]*w)%mod;//累加答案
		}
	}
	return;
}

也可以利用分治和多项式相关知识得到一个 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)的快速插值算法,但比较复杂,博主写快速插值距今已久,刚中考完回归复习拉格朗日插值,故目前能力不足以讲它。

接下来有一个技巧
在部分求解多项式的题目中, x i x_i xi是连续的(相差1),这时如果需要进行单点求值,我们可以将拉格朗日插值公式稍微变形之后得到一种 O ( n ) O(n) O(n)的算法。
x ∈ [ 0 , n ] x\in[0,n] x[0,n]
f ( x ) = ∑ j = 0 n f ( j ) ∏ i = 0 , i ≠ j n x − i j − i f(x)=\sum_{j=0}^nf(j)\prod_{i=0,i\not=j}^n\frac{x-i}{j-i} f(x)=j=0nf(j)i=0,i=jnjixi
= ∑ j = 0 n f ( j ) x ( x − 1 ) ( x − 2 ) . . . ( x − n ) j ( j − 1 ) ( j − 2 ) . . . ⋅ 2 ⋅ 1 ⋅ ( − 1 ) ⋅ ( − 2 ) ⋅ . . . ( j − n + 2 ) ( j − n + 1 ) ( j − n ) =\sum_{j=0}^nf(j)\frac{x(x-1)(x-2)...(x-n)}{j(j-1)(j-2)...\cdot2\cdot1\cdot(-1)\cdot(-2)\cdot...(j-n+2)(j-n+1)(j-n)} =j=0nf(j)j(j1)(j2)...21(1)(2)...(jn+2)(jn+1)(jn)x(x1)(x2)...(xn)
= ∑ j = 0 n f ( j ) ∏ i = 0 n x − i ( − 1 ) n − j ( j − 1 ) ! ( n − j ) ! =\sum_{j=0}^{n}f(j)\frac{\prod_{i=0}^nx-i}{(-1)^{n-j}(j-1)!(n-j)!} =j=0nf(j)(1)nj(j1)!(nj)!i=0nxi
= ∑ j = 0 n ( − 1 ) n − j f ( j ) ∏ i = 0 n x − i ( j − 1 ) ! ( n − j ) ! =\sum_{j=0}^{n}(-1)^{n-j}f(j)\frac{\prod_{i=0}^nx-i}{(j-1)!(n-j)!} =j=0n(1)njf(j)(j1)!(nj)!i=0nxi
预处理一下阶乘和 ∏ i = 0 n x − i \prod_{i=0}^nx-i i=0nxi的值,然后就可以 O ( n ) O(n) O(n)求解了。
如果 x ∈ [ d , d + n ] ] x\in[d,d+n]] x[d,d+n]](d为任意实数),则可令 x ∈ [ 0 , n ] x\in[0,n] x[0,n]求出f,然后将函数在水平方向上平移即可。

这个技巧可以用于很多构造点值求解多项式的题,最经典的一种是求单点自然数幂求和 ( ∑ i = 1 n i k ) (\sum_{i=1}^ni^k) (i=1nik)
经过推导可知这是一个 k + 1 k+1 k+1次多项式(推导过程需用到斯特林数(或伯努利数?),这里放一下TJY大佬利用斯特林数的一种推导方法
于是我们就可以枚举0到k求值,然后得到k+1个横坐标连续的点值,再把n代入用刚刚的技巧 O ( n ) O(n) O(n)单点求值即可。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值