例题:【模板】拉格朗日插值
给你 \(n\) 个点 \((x_i, y_i)\),将过这 \(n\) 个点的最多 \(n-1\) 次的多项式记为 \(f(x)\),求 \(f(k)\) 的值。
- 方法 1:待定系数法
设 \(f(x) = \displaystyle\sum_{i=1}^{n-1}a_x x^i\) ,将每个 \(x_i\) 代入 \(f(x)\),有 \(f(x_i) = y_i\),这样就可以得到由 \(n\) 个 \(n\) 元一次方程所组成的方程组,然后使用 高斯消元 解该方程组的每一项 \(a_i\),就得到了 \(f(x)\) 的表达式。
时间复杂度 \(\mathcal O(n^3)\)。
- 方法 2:拉格朗日插值法
题目要求构造一个函数 \(f(x)\) 过所有点 \(P_i(x_i, y_i)\)。设第 \(i\) 个点在 \(x\) 轴上的投影为 \(P_i^{\prime}(x_i, 0)\)。
考虑构造 \(n\) 个函数 \(f_1(x),f_2(x),...,f_n(x)\),使得对于第 \(i\) 个函数 \(f_i(x)\) ,其图像过 \(\begin{cases}P_j^{\prime}(x_j, 0),(j \not = i) \\ P_i(x_i, y_i) \end{cases}\),则可知题目所求函数 \(f(x) = \displaystyle\sum_{i=1}^{n} f_i(x)\)。
那么可以设 \(f_i(x) = a \times \prod_{j \not = i}(x - x_j)\),将点 \(P_i(x_i, y_i)\) 代入可以知道 \(a = \frac{y}{\prod_{j \not - i} (x - x_j)}\),所以
\[f_i(x) = y_i \times \frac{\prod_{j \not = i}(x - x_j)}{\prod_{j \not = i}(x_i - x_j)} = y_i \times \prod_{j \not = i} \frac{x - x_j}{x_i - x_j} \]那么我们就可以从另外一个角度推导出通常意义下(而非模意义下)拉格朗日插值的式子为:
\[f(x) = \sum_{i=1}^{n} y_i \times \prod_{j \not = i} \frac{x - x_j}{x_i - x_j} \]#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 998244353;
const int MAXN = 1e5 + 10;
int n, K, ans = 0;
int x[MAXN], y[MAXN];
int read() {
int s = 0, f = 0;
char ch = getchar();
while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while(isdigit(ch)) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
int Pow(int x, int p) {
int res = 1;
while(p) {
if(p & 1) res = res * x % mod;
x = x * x % mod, p >>= 1;
}
return res;
}
int Inv(int x) { return Pow(x, mod - 2); }
signed main() {
n = read(), K = read();
for(int i = 1; i <= n; ++i) {
x[i] = read(), y[i] = read();
}
for(int i = 1; i <= n; ++i) {
int fz = 1, fm = 1;
for(int j = 1; j <= n; ++j) {
if(i == j) continue;
fz = fz * (K - x[j]) % mod;
fm = fm * (x[i] - x[j]) % mod;
}
ans = (ans + y[i] * fz % mod * Inv(fm) % mod) % mod;
}
ans = (ans + mod) % mod;
printf("%lld\n", ans);
return 0;
}
另一个例题:
AtCoder ABC208 F - Cumulative Sum