前言

最近在做历年的NOI原题,然后就做到了[NOI2019] 机器人,惊讶地发现我居然没学过拉格朗日插值🤡!

之前的省选题本来有一道拉插的题([省选联考 2022] 填树),但是在 拉格朗日插值图 java生成 拉格朗日插值实际应用_Lagrange插值

简介

粘的别人的
在数值分析中,拉格朗日插值法是以法国18世纪数学家约瑟夫·拉格朗日命名的一种多项式插值方法。如果对实践中的某个物理量进行观测,在若干个不同的地方得到相应的观测值,拉格朗日插值法可以找到一个多项式,其恰好在各个观测的点取到观测到的值。上面这样的多项式就称为拉格朗日(插值)多项式。

拉格朗日插值法

众所周知,给出一个 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_02 次多项式的 拉格朗日插值图 java生成 拉格朗日插值实际应用_数学_03 个点值可以唯一地求出这个多项式,一个朴素的求法就是列出 拉格朗日插值图 java生成 拉格朗日插值实际应用_数学_03 个方程然后使用高斯消元,复杂度 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_05,往往还伴随精度问题。

而拉格朗日插值法可以在 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_06

直接上拉格朗日插值公式:
拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_07这个式子十分巧妙,因为带入后可以发现它刚好能取到所有的点值,并且次数最大为 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_02

用这个公式直接求多项式虽然也是 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_05(还比高消慢),但是是可以优化滴!

我们可以先求出 拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_10,然后枚举 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_11 时先 拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_12 计算下面的 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_13,然后由于 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_14 在计算的时候没有被掐断,所以单个 拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_15 可以整除 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_14,直接 拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_12 递推求出 拉格朗日插值图 java生成 拉格朗日插值实际应用_Lagrange插值_18 即可(注意特判 拉格朗日插值图 java生成 拉格朗日插值实际应用_Lagrange插值_19)。这样总的复杂度就降为了 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_06

求单个点值

这里求单个点值的意思是给出 拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_21,我们需要求 拉格朗日插值图 java生成 拉格朗日插值实际应用_数学_22

我们显然可以直接求出 拉格朗日插值图 java生成 拉格朗日插值实际应用_算法_23 然后带入求解,但是当我们的目的仅仅是求出 拉格朗日插值图 java生成 拉格朗日插值实际应用_数学_22

我们不妨直接带入拉格朗日插值公式:
拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_25由于不再是求多项式,所以我们可以在 拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_12 时间内求出所有的 拉格朗日插值图 java生成 拉格朗日插值实际应用_数学_27,然后每次枚举 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_11 时就只用求 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_13 了。虽然还是 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_06,但是减小了常数且更简单。

O(n)求单个点值

还是只要求求出 拉格朗日插值图 java生成 拉格朗日插值实际应用_数学_22

在多数应用到拉插的题目中,这 拉格朗日插值图 java生成 拉格朗日插值实际应用_数学_03 个点值是满足下标连续,或者等间距的,即 拉格朗日插值图 java生成 拉格朗日插值实际应用_数学_33

此时我们可以做些预处理(比如当间距等于 1 的时候,你需要预处理阶乘的逆元),然后就可以单次 拉格朗日插值图 java生成 拉格朗日插值实际应用_Lagrange插值_34 求出 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_13。(需要特别注意符号问题)

应用

有一个经典问题:计算 拉格朗日插值图 java生成 拉格朗日插值实际应用_算法_36。这个问题显然可以用斯特林反演 拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_37

众所周知这个东西是一个关于 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_02拉格朗日插值图 java生成 拉格朗日插值实际应用_Lagrange插值_39 次多项式,所以我们可以先 拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_40(忽略快速幂,你也可以用线性筛)求出前 拉格朗日插值图 java生成 拉格朗日插值实际应用_算法_41 个点值,然后用上面的方法 拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_40 拉插求出 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_02 处的答案,这样总复杂度只有 拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_40

更实用的场景是在一些DP题中,比如你需要求 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_45 个DP值来转移,但是你发现这 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_45 个点值的函数是一个次数较小的 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_02 次多项式,那么就可以只求前 拉格朗日插值图 java生成 拉格朗日插值实际应用_数学_03

一般要看出这是个多项式需要归纳证明,但是我不会

进阶:快速插值

回到最初的问题上,我们需要求出多项式 拉格朗日插值图 java生成 拉格朗日插值实际应用_算法_49。如果 拉格朗日插值图 java生成 拉格朗日插值实际应用_Lagrange插值_50

我们需要把 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_06

稍微变一下式子:
拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_52但是这个时候式子就变得很奇怪:拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_53

然而,正因为上下两边都是0,我们可以使用洛必达法则:
拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_54所以第一步,我们可以先分治NTT求出 拉格朗日插值图 java生成 拉格朗日插值实际应用_线性代数_14拉格朗日插值图 java生成 拉格朗日插值实际应用_算法_56,然后多项式多点求值求出每一个 拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_57

剩下还有 拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_58 这部分,再用一次分治NTT即可。

于是我们可以在 拉格朗日插值图 java生成 拉格朗日插值实际应用_拉格朗日插值图 java生成_59