拉格朗日插值法
文章可能不是很完善,只是一次模拟赛中的题考到了,于是有了这篇博客。
插值:已知一些离散的数据(点对),求一个函数经过所有离散的数据点。
正文
本来以为会很难,但是确实思想非常简单。
现已知 \(n\) 个点对,\((x_1,y_1),(x_2,y_2)\dots (x_n,y_n)\) ,欲构造出函数 \(F(x)\) 通过这 \(n\) 个点。
放出柿子:\(\displaystyle F(x)=\sum_{i=1}^{n}{y_i\times \frac{\prod_{j\neq i}(x-x_j)}{\prod_{j\neq i}{(x_i-x_j)}}}\)
可以看出,满足经过所有点对。
核心思想:对于每一个点构造一个函数 \(\displaystyle f_i=\frac{\prod_{j\neq i}(x-x_j)}{\prod_{j\neq i}{(x_i-x_j)}}\),使 \(f_i(x_i)=1,f_i(x_j)=0\) ,最后令 \(F(x)=\sum_{i=1}^{n}{y_i*f_i(x)}\) 即可。
核心代码
LL ans = 0;
for (int i = 1; i <= n; i++)
{
int fi = 1;
for (int j = 1; j <= n; j++)
if (j != i) fi = mul(mul(fi, k - t[j].x), inv(t[i].x - t[j].x));
ans = (ans + mul(fi, t[i].y)) % mod;
}
重心拉格朗日插值法
观察普通拉格朗日插值的柿子,发现 \(f_i(x)\) 有很多相似的地方。记 \(\displaystyle t(x)=\prod_{j=1}^{n}{(x-x_j)}, w_i=\frac{1}{\prod_{j\neq i}{(x_i-x_j)}}\)
那么 \(\displaystyle F(x)=\sum_{i=1}^{n}{y_i\frac{t(x)*w_i}{x-x_i}}\)
对于这种方法,每次加一个值过后,就可以做到 \(O(n)\) 修改了。
线性拉格朗日插值法
当 \(n\) 个点是连续的时候,我们可以做到询问线性。
设 \(n\) 个点分别为 \((1,f(1)),(2,f(2))\dots (n,f(n))\)
代入式子就是 \(\displaystyle \sum_{i=1}^{n}{\frac{\prod_{j\neq i}{(x-j)}}{\prod_{j\neq i} (i-j)}}\)
等价于 \(\displaystyle \sum_{i=1}^{n}{f(i)\times (-1)^{n-i}*\frac{\prod_{j\neq i}{(x-j)}}{(i-1)!(n-i)!}}\)
预处理出 \((x-j)\) 的前后缀积即可。
具体来讲:预处理 \((x-j)\) 的前后缀积 \(pre[i], suf[i]\),每次分母的计算就可以直接 \(pre[i-1]*suf[n-i]\)