拉格朗日插值法
参考资料
参考资料
简介
插值
在离散数据的基础上补插连续的函数,使得这条连续函数经过所有离散数据点,这个过程就叫插值。
其意义在于:
插值是离散函数逼近的重要方法,利用它可通过函数在有限个点处的取值状况,估算出函数在其他点处的近似值。
拉格朗日插值法
其核心思想在于直接硬性配凑,先分成不同的子函数,在合并成一个新的函数,很多时候只需要知道 \(O\)。
引入
模板题
给定 \(n\) 个点 \((x_i, y_i)\),满足所有 \(x_i\) 互不相同,则存在唯一次数不超过 \(n-1\) 的多项式 \(y=f(x)\) 经过这些点。要求确定该多项式并计算 \(f(k) \bmod 998244353\)。
\(n \le 2\times 10^3,\ 1 \le x_i, y_i, k < 998244353\),\(x_i\) 两两不同。
解法
基础
我们对每个点构造一个子函数,令其只在该点取值为 1,否则为 0。
也就是说,我们要计算 $ n $ 个子函数,第 $ i $ 个子函数为:
那么插值的结果就是:
对于一般形式:对于 $ n $ 个点 \((x_1, y_1), (x_2, y_2), \dots, (x_n, y_n)\) (\(x_1 < x_2 < \cdots < x_n\)),设:
那么插值结果就是:
直接算上面这个求和式子就可以得到 \(O(n^2)\) 的做法,我们可以通过一些小小的变形变成 \(O(n^2)\) 预处理 \(O(n)\) 查询,具体看重心拉格朗日差值。
code
ll ans=0;
for(int i=1;i<=n;i++){
ll p=1,q=1;
for(int j=1;j<=n;j++) if(j!=i) {
p=p*(k-x[j]+mod)%mod;
q=q*(x[i]-x[j]+mod)%mod;
}
ans=(ans + y[i]%mod*p%mod*inv(q)%mod)%mod;
}
拉插其实是将 \(k+1\) 个点值表示成 \(k\) 次多项式,所以如果你想求一个 \(k\) 次多项式的值,我们需要知道 \(k+2\) 个点值。
拓展
当 \(x_i\) 连续
我们将原来的式子替换为
其中,\(pre_i,suf_i\) 分别表示 \(k-x_j\) 的前缀积和后缀积。
由于 \(x_i\) 是连续的,所以 \(x_i-x_{i-1}\) 差值固定,因此可以进行预处理。比如说,常见的对于 \(x_i-x_{i-1}=1\),我们就可以预处理阶乘及其逆元。把式子改写成
然后我们就得到了 \(O(n)\) 的做法。
重心拉格朗日差值法
动态加点,可以做到 \(O(n)\) 修改,\(O(n)\) 查询。
重写原来的式子
令 \(g=\prod_j (k-x_j)\),于是可以将原来的式子改写成
其中 \(w_i={\prod_{j\neq i} (x_i-x_j)}\),每次插入一个新点是,这个是可以 \(O(n)\) 动态维护的。
注意: 如果 \(x_i\) 是连续的,重心拉格朗日差值法不如上面的做法。
多项式快速插值
这可以做到 \(O(n\log^2 n)\),但这并不在我们的讨论范围之内。
应用
一、多项式差值
暂时不会,可以参考一下资料 1。
二、求自然数幂和
除了拉插还有其他很多其他方法。由于这里是拉插文章,这里就讲拉插做法。
我们可以通过一些神秘方法(比如说差分/扰动法)知道一个重要结论:\(\sum_{i=1}^n i^k\) 可以表示成一个关于 \(n\) 的 \(k+1\) 次多项式。
现在问题变成我们要算出这个 \(k+1\) 次多项式的在 \(n\) 这个位置的单点值,我们要用拉插的前提条件是要先得出 \(k+2\) 个点值,于是我们算出 \(1\sim k+2\) 的点值,带入拉插式子中,又由于我们选择的横坐标是连续的,所以我们可以预处理从而做到 \(O(k)\) 的复杂度,当然由于算点值带个 \(\log\),所以总复杂度是 \(O(k\log k)\)。
补充一下:其实可以做到 \(O(k)\)。
因为 \(i^k\) 这个是积性函数,所以只用算出质数位置上的 \(p^k\),然后用线性筛算出来,前缀和一下即可,复杂度 \(O({k\over \ln k}\log_2 k)\)。
三、优化DP
注意事项
-
重心拉格朗日差值法在 \(x_i\) 连续时表现不是最佳。
-
拉插其实是将 \(k+1\) 个点值表示成 \(k\) 次多项式,所以如果你想求一个 \(k\) 次多项式的值,我们需要知道 \(k+2\) 个点值。
题目
P4781 【模板】拉格朗日插值 \(\checkmark\)
其实就是上面的引入。
P5667 拉格朗日插值2
题目大意
给定不超过 \(n\) 次多项式的 \(n+1\) 个点值 \(f(0),f(1),\cdots,f(n)\) 和正整数 \(m\),求 \(f(m),f(m+1),\cdots,f(m+n)\) 对 998244353 取模。
\(n\le 1.6\times 10^5,m\le 10^8\)。
解题思路
这个需要掌握 NTT,暂时不会。
CF622F The Sum of the k-th Powers \(\checkmark\)
就是第二个应用。
P4593 [TJOI2018] 教科书般的亵渎 \(\checkmark\)
题目大意
所有可能血量为 \(1\sim n\) 的点,其中缺失 \(m\) 个点。每次操作:将所有当前点坐标减 \(1\),若有点变为 \(0\) 则移除并连锁(连锁不额外计分,不计入操作次数)。杀死所有点所需操作次数等于剩余点的连续段数 \(k\)。每次操作,对每个被操作的点,若其操作前坐标为 \(x\),则贡献 \(x^k\) 分。求总分 \(\bmod 10^9+7\)。
\(T\le 10,\ n\le 10^{13},\ m\le 50,\ 1\le a_i<n\)。
解题思路
容易发现 \(k=m+1-len\),\(len\) 是从 \(n\) 开始有连续的空缺。
然后就是计算 \(\sum_{i=1}^n i^k\) 再减去空缺位置的贡献,注意:答案是每次操作贡献的答案累加,所以每次都要重新计算一下,实现自己推一推就行了,具体也可以看看代码。计算就是应用二。复杂度就是 \(O(Tm^2)\)。这篇文章会 hack 掉不勤奋取模。

浙公网安备 33010602011771号