【模板】拉格朗日插值

【模板】拉格朗日插值

不会中国剩余定理的戳 → \to 【模板】中国剩余定理

Part 1. 拉格朗日插值是干什么的

用于求解如下的问题:

给出 n n n 个点 ( x i , y i ) (x_i,y_i) (xi,yi),保证 x i x_i xi 互不相等,记最多 n − 1 n-1 n1 次的多项式函数 f ( x ) f(x) f(x) 经过这 n n n 个点,求出 f ( k ) f(k) f(k)

Part 2. 拉格朗日插值

对于任意的 a a a,我们都有 f ( x ) ≡ f ( a ) ( m o d x − a ) f(x)\equiv f(a)\pmod {x-a} f(x)f(a)(modxa)
那么根据中国剩余定理(CRT),可以得到关于 f ( x ) f(x) f(x) 的线性同余方程组:

{ f ( x ) ≡ y 1 ( m o d x − x 1 ) f ( x ) ≡ y 2 ( m o d x − x 2 ) f ( x ) ≡ y 3 ( m o d x − x 3 )                                  ⋮ f ( x ) ≡ y n ( m o d x − x n ) \begin{cases} f(x)\equiv y_1\pmod{x-x_1}\\ f(x)\equiv y_2\pmod{x-x_2}\\ f(x)\equiv y_3\pmod{x-x_3}\\ \;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\vdots\\ f(x)\equiv y_n\pmod{x-x_n}\\ \end{cases} f(x)y1(modxx1)f(x)y2(modxx2)f(x)y3(modxx3)f(x)yn(modxxn)

根据中国剩余定理,我们设 M = ∏ i = 1 , x i ≠ x n ( x − x i ) M=\prod\limits_{i=1,x_i\neq x}^n (x-x_i) M=i=1,xi=xn(xxi),对应地 m i = M x − x i m_i=\dfrac{M}{x-x_i} mi=xxiM(这是 CRT 基础内容)。
m i m_i mi 在模 x − x i x-x_i xxi 意义下的逆元为:
inv ⁡ ( m i ) = ∏ j ≠ i ( x i − x j ) \operatorname{inv}(m_i)=\prod_{j\neq i} (x_i-x_j) inv(mi)=j=i(xixj)
由于线性同余方程组在模 M M M 下有唯一解,故得到拉格朗日插值表达式为:
f ( x ) ≡ ∑ i = 1 n y i ∏ j ≠ i x − x j x i − x j ( m o d M ) f(x)\equiv \sum\limits_{i=1}^ny_i\prod_{j\neq i}\dfrac{x-x_j}{x_i-x_j} \pmod M f(x)i=1nyij=ixixjxxj(modM)

考虑我们要求出 f ( k ) f(k) f(k),带入 x = k x=k x=k 即可。求解逆元可以考虑先将分子与分母处理完,再求解逆元。
时间复杂度 O ( n 2 ) \mathcal{O}(n^2) O(n2)

#include
#define int long long
using namespace std;
const int N=5e5+5;
inline int read(){
    char op=getchar();
    int w=0,s=1;
    while(op<'0'||op>'9'){
        if(op=='-') s=-1;
        op=getchar();
    }
    while(op>='0'&&op<='9'){
        w=(w<<1)+(w<<3)+op-'0';
        op=getchar();
    }
    return w*s;
}
const int mod=998244353;
int Mul(int a,int b){return (a%mod*b%mod)%mod;}
int Add(int a,int b){return (a+b)%mod;}
int Dec(int a,int b){return (a-b+mod)%mod;}
int Pow(int a,int k){
    int ans=1;
    while(k){
        if(k&1) ans=Mul(ans,a);
        a=Mul(a,a);
        k>>=1;
    }
    return ans;
}
int inv(int x){return Pow(x,mod-2);}
int x[N],y[N],n,m;
int solve(int i){
    int ans=y[i],s1=1,s2=1;
    for(register int j=1;j<=n;j++){
        if(i==j) continue;
        s1=Mul(s1,m-x[j]);
        s2=Mul(s2,x[i]-x[j]);
    }
    ans=Mul(ans,Mul(s1,inv(s2)));
    return ans;
}
signed main(){
    n=read(),m=read();
    int ans=0;
    for(register int i=1;i<=n;i++) x[i]=read(),y[i]=read();
    for(register int i=1;i<=n;i++) ans=Add(ans,solve(i));
    printf("%lld\n",Add(ans,mod));
}

你可能感兴趣的:(数论-多项式,算法)