题解:P4781 【模板】拉格朗日插值
学生听了 \(\infty\) 道拉格朗日插值的题,于是来学学。
设第 \(i\) 个点 \(P_i(x_i,y_i)\) 在 \(x\) 轴上的投影为 \(P^{\prime}_i(x_i,0)\)。
那么考虑构造一个函数 \(f_x(i)\) 经过点 \(\begin{cases} P_i(x_i,y_i) \\ P^{\prime}_{j}(x_j,0) & j\neq i \\\end{cases}\)。
那么我们最终求的函数 \(f(x)\) 则为 \(\sum^n_{i=1} f_i(x)\)。
Proof: 当 \(x = x_1\) 的时候 \(f(x_1) = y_1 + \sum^n_{i = 2} 0 = y_1\),当 \(x = x_2\) 的时候 \(f(x_2) = 0 + y_2 + \sum^n_{i=3}0 = y_2\)。依此类推。
那么此时我们的问题就变成了如何构造一个 \(f_i(x)\)。
根据初中的因式定理即当 \(f_i(x_j) = 0\) 时,\(f_i(x)\) 必定包含 \((x - x_j)\) 这一个因式。所以我们考虑将 \(f_i(x)\) 表示为 \(a \prod_{j \neq i}^n (x - x_j)\)。
那么此时考虑将点 \(P_i(x_i,y_i)\) 带入 \(f_i(x)\) 得:
将 \(a\) 带回原式得:
既然已经有了所有的 \(f_i(x)\) 了,\(f(x)\) 就是 \(\sum^n_{i = 1} y_i \prod^n_{j \neq i} \dfrac{x - x_j}{x_i - x_j}\)。
那么对于本题 \(\mathrm O(n^2)\) 就能过了。
code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 2e3 + 10;
const int mod = 998244353;
int qpow(int a,int b)
{
    int res = 1;
    while(b)
    {
        if(b & 1)res = res * a % mod;
        a = a * a % mod;b >>= 1;
    }
    return res;
}
int n,k,x[maxn],y[maxn];
int f(int k)
{
    int ans = 0;
    for(int i = 1;i <= n;i++)
    {
        int p = 1,q = 1;
        for(int j = 1;j <= n;j++)if(i != j)p = p * (k - x[j]) % mod,q = q * (x[i] - x[j]) % mod;
        ans = (ans + p * qpow(q,mod - 2) % mod * y[i] % mod) % mod;
    }
    return (ans % mod + mod) % mod;
}
signed main()
{
    cin >> n >> k;
    for(int i = 1;i <= n;i++)cin >> x[i] >> y[i];
    cout << f(k);
    return 0;
}
那么假如我们要插入一些点呢?但是我们注意到每次新加入一个点的时候要重新插值,如果要多次增加点,那么我们不就炸了吗?
此时我们再次回看此前的式子:
考虑设 \(g = \prod^n_{i = 1}(x - x_i)\),则 \(f_i(x)\) 就被我们化为了:
那么此时设 \(t_i = \dfrac{y_i}{\prod^n_{j \neq i}(x_i - x_j)}\)。则:
然而你发现你对于一个新加入的点,你只需要求出 \(t_i\) 即可。一次是 \(\mathrm O(n)\) 的。那么加入 \(n\) 个点,我们在任何时间去查询 \(f(x)\) 都是 \(\mathrm O(n^2)\) 的。

                
            
        
浙公网安备 33010602011771号