拉格朗日插值法

拉普兰德 拉格朗日差值法,它可以通过\(n\)个点来构造出一个\(n-1\)次多项式\(f(x)\)(恩。应该是最多\(n-1\)次,因为有些高次项的系数可能是\(0\))。

8说了。。。康题:P4781 【模板】拉格朗日插值

题意:给\(n\)个点\((x_1,y_1),\dots,(x_n,y_n)\),你要构造出一个多项式\(f(x)\),使得\(\forall 1\le i \le n,f(x_i) = y_i\),再给一个\(k\),你需要输出\(f(k)\)的值。

然后拉格朗日差值这个神仙东西就横空出世了~

它的想法就是我是否能构造出\(n\)个多项式\(\ell_1(x),\ell_2(x),\dots,\ell_n(x)\),使得\(\forall 1\le i \le n\),有
\[ \ell_i(x_j) = \begin{cases}1 \quad (j = i) \\0 \quad (j \not= i)\end{cases} \]
(对其他的\(x\)并没有要求)

那么结论就是显然可以,并且
\[ \ell_{i}(x) = \prod\limits_{j \not= i} \frac{x - x_j}{x_i - x_j} \quad (1\le i,j \le n) \]
这个显然是对的吧!

当\(x = x_i\)时,\(\frac{x - x_j}{x_i - x_j} = \frac{x_i - x_j}{x_i - x_j} = 1\),所以后面的所有因式都是\(1\),他们的乘积自然也是\(1\)。

当\(x = x_k \ (k \not= i)\)(em...这里的\(k\)和题面上的不是同一个人),显然会有一个不等于\(i\)的\(j\),使得\(x_k - x_j = 0\),换句话说会有一个因式满足\(\frac{x - x_j}{x_i - x_j} = 0\)。

然后再看回来,既然我们构造出了\(\ell_{i}(x)\),那么\(f(x)\)很好构造吧
\[ f(x) = \sum\limits_{i = 1} ^ n y_i \ell_{i}(x) = \sum\limits_{i = 1} ^ n y_i \prod\limits_{j \not= i} \frac{x - x_j}{x_i - x_j} \]
根据\(\ell_{i}(x)\)的性质,容易验证\(f(x_1) = y_1, f(x_2) = y_2,\dots,f(x_n) = y_n\)。

妙啊~~

好,然后看一下板子题的范围\(1 \le n \le 2 \times 10^3\),恩,直接把\(k\)代进去,算就完了,复杂度$ O(n^2)$

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int P=998244353;
inline int fpow(int a,int b){
    int ret=1; for (;b;b>>=1,a=1ll*a*a%P) if (b&1) ret=1ll*ret*a%P;
    return ret; 
}
#define normal(x) (((x)%P+P)%P)
#define inv(x) (fpow((x),P-2))
const int N=2010;
int lagrange(int *x,int *y,int n,int k){
    int ans=0;
    for (int i=1;i<=n;i++){
        ll tmp=y[i]%P;
        for (int j=1;j<=n;j++) if (j!=i)
            tmp=1ll*tmp*inv(normal(x[i]-x[j]))%P*normal(k-x[j])%P;
        ans=(ans+tmp)%P;
    }
    return ans;
}
int x[N],y[N],K,n;
int main(){
    scanf("%d%d",&n,&K);
    for (int i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]);
    printf("%d\n",lagrange(x,y,n,K));
    return 0;
}
上一篇:matplotlib学习日记(十)-共享绘图区域的坐标轴


下一篇:Linux Socket 编程简介 【转载】