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;
}
posted @ 2026-03-02 09:53  constexpr_ll  阅读(3)  评论(0)    收藏  举报