P4781 学习笔记 & 拉格朗日插值法详解
拉格朗日插值法
拉格朗日插值法是一种简单经典的多项式插值法,它通过构造一个不超过 \(n-1\) 次的多项式来确定平面上的 \(n\) 个点 \((x_i,y_i)\)
即给定 \(n\) 个有序对 \((x_i,y_i)\),求一个函数 \(f(x)\),使得 \(f(x_i)=y_i\)。
怎么构造呢?
拉格朗日插值多项式:
\[L(x)=\sum_{i=1}^n \ell_i(x) \cdot y_i
\]
其中 \(\ell_i(x)\) 称为拉格朗日基函数(插值基函数)
\[\ell_i(x)=\prod_{j \ne i} \frac{x-x_j}{x_i-x_j}
\]
且这个函数有一个神奇的性质:
\[\ell_i(x_k)=
\begin{cases}
0 & k \ne i\\
1 & k=i\\
\end{cases}
\]
这个性质使得 \(L(x_i)\) 必等于 \(y_i\)。(易证,略)
P4781
就是刚刚讲的拉格朗日插值法的模板题啊,计算上面的式子即可。
这里需要对乘起来后的分母求逆元,注意到模数 \(998244353\) 为质数,可以使用费马小定理求逆元。
code
#include <bits/stdc++.h>
#define pub public:
#define pri private:
#define fri friend:
#define Ofile(s) freopen(s".in", "r", stdin), freopen (s".out", "w", stdout)
#define Cfile(s) fclose(stdin), fclose(stdout)
#define fast ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
using namespace std;
using ll = long long;
using ull = unsigned long long;
using lb = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using pil = pair<int, ll>;
using pli = pair<ll, int>;
constexpr int mod = 998244353;
constexpr int maxn = 2e3 + 5;
ll n, k;
ll num, den, ans, tmp;
ll x[maxn];
ll y[maxn];
ll getmod(ll p){
return (p + mod) % mod;
}
ll binpow(ll p, ll q){
ll res = 1;
while (q){
if (q & 1)
res = getmod(res * p);
p = getmod(p * p);
q >>= 1;
}
return res;
}
int main() {
freopen("std.in", "r", stdin);
freopen("std.out", "w", stdout);
fast;
cin >> n >> k;
for (ll i = 1; i <= n; i++)
cin >> x[i] >> y[i];
for (ll i = 1; i <= n; i++)
if (k == x[i])
return cout << getmod(y[i]), 0;
for (ll i = 1; i <= n; i++){
num = den = 1;
for (ll j = 1; j <= n; j++)
if (i - j)
num = getmod(num * (k - x[j])),
den = getmod(den * (x[i] - x[j]));
tmp = getmod(getmod(getmod(y[i]) * getmod(num)) * getmod(binpow(den, mod - 2)));
ans = getmod(ans + tmp);
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号