拉格朗日插值法

概述

  • 拉格朗日插值法(下简称拉插)是一种多项式单点求值的算法。

  • 对于任意的 \(K\) 次多项式,我们可以利用其已知的 \(K+1\) 个或更多的点唯一确定该多项式的形式,且拥有比高消更为优秀的复杂度。

实现原理

  • 在已知 \(K\) 次多项式 \(f(x)\)\(K+1\) 个点后,我们可以利用 Gauss 消元来 \(O(K^3)\) 地求出其各项系数,查询复杂度则是 \(O(K)\)。注意到明显的不平衡,设法设计一种方式能 \(O(K^2)\) 之类地同时支持构建和查询。

  • 不妨记已知点为 \((k,v)\),考虑构建这么一个多项式:\(f(x)=\sum\limits_{i=1}^{K+1} v_i\times g_i(x)\),使得 \(g_i(x)=\begin{cases} 1 & x=k_i\\ 0 & otherwise\end{cases}\)

  • 可以证明该函数符合已知的 \(K+1\) 个点,于是其唯一确定,从而该函数即为原函数。

  • 考虑 \(g\),可以这么配 \(g\)\(g_i(x)=\prod\limits_{j\ne i}^{} \dfrac{x-k_j}{k_i-k_j}\)。目的在于使得 \(x=k_i\) 时,分子分母全部互相消去, \(x\ne k_i\) 时,有一项分子为 \(0\) 的效果。

  • 综合得 \(f(x)=\sum\limits_{i=1}^{K+1} v_i \times \prod\limits_{j\ne i}^{} \dfrac{x-k_j}{k_i-k_j}\) ,可以在 \(n^2\) 的时间内求值,并且可以在模意义下进行。

  • 一个小 tip:把一个 \(K\) 次多项式认为成 \(K+?(?\geqslant0)\) 次多项式是合法的,因为这相当于高次项系数赋成 \(0\)。在不是很确定到底是多少次的时候,强烈建议 \(+7/+10/...\),以防由于前缀和/差分/...带来的升次而挂掉。

连续性拉插优化

  • 在我们自行构造的多项式中,可以考虑将 \(k\) 取连续的 \(1\sim n\)。此时会有非常美妙的性质:

  • 原式可以化为 \(f(x)=\sum\limits_{i=1}^{k+1} v_i\times \dfrac{\prod\limits_{j\ne i}^{} x-j}{\prod\limits_{j\ne i}^{} i-j}\)

  • 对于分子,可以 \(O(n)\) 求前缀积与后缀积;

  • 对于分母,显而易见它是一个类阶乘 \((i-1)!\times (-1)^{K+1-i}\times (K+1-i)!\) 。进一步地,其逆元是可以预处理的。

  • 所以能把 \(O(n^2)\) 优化到 \(O(n)\),比较常见的用法是在确保是多项式的 dp 中加速求解,如 \(\text{P5469 [NOI2019] 机器人}\)

  • 下面给出优化版本的封装函数式代码,其中 \(K\) 为多项式次数,\(k\) 为所求点。

il ll lagrange(ll K,ll k){
	static ll prof[maxk],prob[maxk],numer,denom,ret;//prod
	prof[0]=prob[K+2]=1,ret=0;
	for(ll i=1;i<=K+1;++i) prof[i]=prof[i-1]*(k-i)%mod;
	for(ll i=K+1;i;--i) prob[i]=prob[i+1]*(k-i)%mod;
	
	For(i,1,K+1){
		numer=prof[i-1]*prob[i+1]%mod; if(numer<0) numer+=mod;
		denom=finv[i-1]*finv[K+1-i]%mod;
		if((K+1-i)&1 && denom) denom=mod-denom;//需要考虑 denom=0 的情况
		ret=(ret+v[i]*numer%mod*denom)%mod;
	}
	return ret;
}

例题

P5469 [NOI2019] 机器人

23.1.12 T1 实用和

  • 版权原因,请移步查看。同校的可以找我要截图。
posted @ 2023-01-12 20:10  未欣  阅读(487)  评论(0编辑  收藏  举报