愛德華差值法?(卡格朗日差值法)

前(che)言(dan)

拉格朗日插值法最先被英國數學家愛德華·華林於1779年發現,不久後(1783年)由萊昂哈德·歐拉再次發現。1795年,拉格朗日在其著做《師範學校數學基礎教程》中發表了這個插值方法,今後他的名字就和這個方法聯繫在一塊兒。html

因此我把拉格朗日插值法叫作愛德華插值法ios

那麼這個東西能夠作什麼呢?
知道一個 \(N\) 次多項式函數上的 \(N+1\) 個不一樣的點就能夠求得這個 \(N\) 次多項式。
或者說給出 \(N+1\) 個點 \((x_i, y_i)\)(保證 \(x_i\) 互不相同),要求找出一個過全部點的多項式函數 \(f(x)\)
這個過 \(N+1\) 個點的 \(N\) 次多項式是惟一的。N+1點肯定一條直線
時間複雜度 \(O(n^2)\)函數

原理

拉格朗日插值法這個名字聽起來很厲害。可是原理簡單得讓人吃驚。
對於每一個點,咱們嘗試找出一個函數 \(f_i(x)\),使得 \(f_i(x_i) = y_i\),而且對於其餘的全部橫座標 \(x_j(j\neq i)\)\(f_i(x_j) = 0\)。那麼把 \(n\)\(f_i(x)\) 加起來就能獲得要求的函數 \(f(x)\)
那麼如何找到函數 \(f_i(x)\) 呢?
\[f_i(x) = y_i∏_{j\neq i}\frac{x − x_j}{x_i − x_j}\]
發現當 \(x=x_i\) 的時候連乘的每一項都是1因此 \(∏_{j\neq i}\frac{x − x_j}{x_i − x_j}=1\),當 \(x=x_j\) 的時候連乘至少有一項爲0 \(∏_{j\neq i}\frac{x − x_j}{x_i − x_j}=0\)
進而得出要求的函數 \(f(x)\) 爲:
\[f(x) = \sum _{i=1}^{n}y_i ∏_{j\neq i}\frac{x − x_j}{x_i − x_j}\]
而後呢?就結束了呀!優化

時間複雜度

若是你要求函數某一個點的值,直接把 \(x\) 代進去算,複雜度 \(O(n^2)\)
若是要求多項式係數,直接暴力算是 \(O(n^3)\) 的。
可是考慮預處理出一個多項式 \(P(x) = ∏_{i=1}^{n}(x − x_i)\),每次用 \(P(x)\) 除一下 \(x − x_i\) 就能夠獲得要求的乘積了。時間複雜度優化到了 \(O(n^2)\)spa

板子

模板題code

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define int long long
const int N=3000;;
const int mod=998244353;
int n,k,x[N],y[N],ans;
int ksm(int x,int b){
    int tmp=1;
    while(b){
        if(b&1)tmp=tmp*x%mod;
        b>>=1;
        x=x*x%mod;
    }
    return tmp;
}
int read(){
    int sum=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    return sum*f;
}
signed main(){
    n=read(),k=read();
    for(int i=1;i<=n;i++)x[i]=read()%mod,y[i]=read()%mod;
    for(int i=1;i<=n;i++){
        int tmp=y[i];
        for(int j=1;j<=n;j++){
            if(i==j)continue;
            tmp=tmp*((k-x[j]+mod)%mod)%mod*ksm((x[i]-x[j]+mod)%mod,mod-2)%mod;
        }
        ans=(ans+tmp)%mod;
    }
    printf("%lld",ans);
    return 0;
}

若是以爲我講得很差,佷正常!
而後推薦此博客htm

相關文章
相關標籤/搜索