Loading

拉格朗日插值法

没啥意义

话说我是不是该反思一下为什么我现在才开始学这个玩意?

有啥意义

概念&板板

拉格朗日插值法 (Lagrange Interpolation Polynomial)

在数值分析中,拉格朗日插值法是以法国十八世纪数学家约瑟夫·拉格朗日命名的一种多项式插值方法。许多实际问题中都用函数来表示某种内在联系或规律,而不少函数都只能通过实验和观测来了解。如对实践中的某个物理量进行观测,在若干个不同的地方得到相应的观测值,拉格朗日插值法可以找到一个多项式,其恰好在各个观测的点取到观测到的值。这样的多项式称为拉格朗日(插值)多项式。数学上来说,拉格朗日插值法可以给出一个恰好穿过二维平面上若干个已知点的多项式函数。(贺自百度百科

我看大家拉插博客好像都写了个这个捏,那我还是随大流吧。

具体来说就是已知几个点,它们构成函数,然后你随便扔个横坐标进去求一下函数值。

可爱的拉格朗日叔叔脑子总是这么好使,它使用 \(n\) 个构成方式一样的函数(\(n\) 是平面上最初点的个数)使他们加起来等于最后我要的函数。

具体的先引入小学知识点:

给定平面上 \(n\) 个点可以唯一确定一个 \(n - 1\) 次函数。

那就算我知道这个我也只有小学水平没法比得上拉格朗日叔叔啊。

好的那这样我们举一个简简单单的小例子:

\[f(x) = ax^3 + bx^2 + cx + d \]

也就是说我平面上给了四个点。

考虑可加性的具体意义,那就是:

没啥意义,就是直接加!

考虑对于每个点做出一个过这个点的函数: \(g_i(x)\)

既然每个位置都有了,那我有点懒,我想把第 \(i\) 个函数在 \(x_i\) 的取值直接设成 \(y_i\)

可是这样其他 \(n - 1\) 个横坐标对应直接成 \(0\) 了啊……

可以不?可爱的拉格朗日插值法叔叔说:

当然可以捏!O(∩_∩)O~~我也是懒人!

没错,他就是这么干的,但是为了加起来看着好看一点,你起码能不能长得差不多啊?

考虑这个函数具体长相:

首先是个连续函数(不然有点逆天,不是咋加?)

然后只有 \(i\)\(y_i\),其他给定的点值都为 \(0\)

拉格朗日叔叔给的构造是这样的:

\[g_i(x) = y_i\prod_{i \not = j}\frac{x - x_j}{x_i - x_j} \]

他好像真的满足诶……那直接一加:

\[f(x) = \sum_{i = 1}^{n}g_i(x) = \sum_{i = 1}^{n}y_i\prod_{i \not = j}\frac{x - x_j}{x_i - x_j} \]

然后你就发现你做完了。

emm,有点简单,统计一遍答案是 \(\mathcal{O}(n^2)\)

CODE
#include <bits/stdc++.h>
typedef long long ll; 
using namespace std; 
const int N = 5e5 + 100; 
const int mod = 998244353; 

int n, K; 
struct node {
	ll x, y; 
} a[N]; 

inline ll Quick_Pow(ll a, ll b) {
	ll ans = 1; 
	while (b) {
		if (b & 1) ans = (ans * a) % mod; 
		b >>= 1, a = (a * a) % mod; 
	}
	return ans; 
}
inline ll Lagrange(int n, int x) {
	ll ans = 0; 
	for (int i = 1; i <= n; ++ i) {
		ll now = a[i].y; 
		for (int j = 1; j <= n; ++ j) {
			if (j == i) continue; 
			now = now * (x - a[j].x + mod) % mod * Quick_Pow((a[i].x - a[j].x + mod) % mod, mod - 2) % mod; 
		}
		(ans += now) %= mod; 
	}
	return ans; 
}

signed main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); 
	cin >> n >> K; 
	for (int i = 1; i <= n; ++ i) cin >> a[i].x >> a[i].y; 
	cout << Lagrange(n, K); 
}

延续(?可爱捏)

但是上述情况其实并不是特别食用,最多的还是给你个递归式,然后随便插几个点。

我认为可爱的拉格朗日叔叔那个没有计算机的年代应该是不知道优化时间复杂度的,就和隔壁的傅里叶叔叔一样。

所以应该是哪个可爱的后人叔叔发现并整理的。

其实意思是啥呢,就是把原来是式子中的 \(x_i\) 换成 \(i\) 问你咋处理更优秀。

我们默认 \(x > n\) 因为如果反之我们可以 \(\mathcal{O}(1)\) 求。

然后我们直接化:

\[\begin{aligned} f(x) = \sum_{i = 1}^ny_i\prod_{i \not = j}\frac{x - j}{i - j} \end{aligned} \]

直接提分子发现它是 \(\dfrac{\prod\limits_{i \not = j}x - j}{x - i}\)

简化是: \(numerator = \dfrac{(x - 1)!}{x - i}\)

分母的话有点复杂,应该是两个阶乘乘积形式: \(dinominator = (-1)^{n - i}\times (i - 1)! \times (n - i)!\)

所以就是这样的:

\[f(x) = \sum_{i = 1}^ny_i\frac{(x - 1)!}{(-1)^{n - i}\times (i - 1)! \times (n - i)! \times (x - i)} \]

如果可以预处理逆元复杂度线性,否则为 \(\mathcal{O}(n \log n)\)

好像还有什么重心拉格朗日插值,但我觉得没啥意义直接跳了

应用

比较实用的就是求 \(k\) 次幂和

即: \(f(x) = \sum\limits_{i = 1}^xi^k\)

具体,请看下回

因式分解。

posted @ 2024-11-25 16:48  HANGRY_Sol&Cekas  阅读(58)  评论(4编辑  收藏  举报