1. 程式人生 > >拉格朗日插值法

拉格朗日插值法

說明 -1 需要 插值 是什麽 col pre rac div

  給定 $n$ 個點 $(x_1, y_1), (x_2, y_2), ..., (x_n, y_n)$ , 其中 $x_1, x_2, ..., x_n$ 互不相等, 構造一個最高次不超過 $n-1$ 的多項式 $F(x)$ 過這 $n$ 個點.

  首先, 這個多項式有且僅有一個, 我們可以通過範德蒙矩陣有逆來說明, 接下來考慮構造.

  構造 $C_1(x), C_2(x), ..., C_n(x)$ , 其中 $C_i(x) = \left\{ \begin{aligned} 1, & x = x_i \\ 0, & x \ne x_i \end{aligned} \right.$ , 那麽 $F(x) = \sum_{i = 1} ^ n C_i(x) y_i$ .

  先連乘上 $(n-1)$ 項 $(x - x_j)$ 使得 $\forall k \ne i, C_i(x_k) = 0$ , 再來保證第 $i$ 項滿足 $C_i(x_i) = 1$, 構造得 $\begin{aligned} C_i(x) = \frac{\prod_{j \ne i} (x - x_j)}{\prod_{j \ne i} (x_i - x_j)} \end{aligned}$ .

  綜上, 滿足插值條件且最高次不超過 $n-1$ 次的多項式有且僅有 $\begin{aligned} F(x) = \sum_{i = 1} ^ n y_i \frac{ \prod_{k \ne i} (x - x_k)}{\prod_{k \ne i} (x_i - x_k)} \end{aligned}$ .  

  如果已經知道一個 $n$ 次多項式 $F(x)$ 的 $n+1$ 個點, 要反著求 $F(x)$ , 那麽可以直接把 $n+1$ 個點代入拉格朗日插值法, 因為我們可以得到唯一的滿足插值條件且最高次不超過 $n$ 的多項式, 而我們知道存在 $F(x)$ 滿足這兩個條件, 所以得到的就是 $F(x)$ .

  如果已經知道一個 $n$ 次多項式 $F(x)$ 的 $n+2$ 個點, 要反著求 $F(x)$ , 那麽可以直接把 $n+2$ 個點代入拉格朗日插值法, 因為我們可以得到唯一的滿足插值條件且最高次不超過 $n+1$ 的多項式, 而我們知道存在 $F(x)$ 滿足這兩個條件, 所以得到的就是 $F(x)$ .

  總之, 如果我們知道 $n$ 次多項式 $F(x)$ 的不少於 $n+1$ 個點, 那麽可以直接將這些點代入拉格朗日插值法中, 反著求出 $F(x)$ . 也就不需要精細到恰好要代入多少個點, 這樣會好實現很多.

  假如我把一個 $n$ 次多項式 $F(x)$ 的 $n$ 個點代入拉格朗日插值法中, 得到的又是什麽? 根據相關理論, 得到的就是滿足插值條件, 且最高次不超過 $n-1$ 次的多項式, 這個多項式與 $F(x)$ 沒有半毛錢關系.

  給定 $n$ 個點, 求 $f(X)$ .

  時間復雜度為 $O(n ^ 2)$ .

 1 int Solve(int X) {
 2     int fx = 0;
 3     for (int i = 1; i <= n; i++) {
 4         int Up = 1, Dw = 1;
 5         for (int j = 1; j <= n; j++) if (i != j) {
 6             Up = 1LL * Up * (X - x[j]) % MOD;
 7             Dw = 1LL * Dw * (x[i] - x[j]) % MOD;
 8         }
 9         fx = (fx + 1LL * y[i] * Up % MOD * Inv(Dw)) % MOD;
10     }
11     return fx;
12 }

  給定 $n$ 個點, 求多項式 $f(x)$ 的系數表示.

  時間復雜度為 $O(n ^ 2)$ .

 1 void Solve(void) {
 2     memset(ans, 0, sizeof ans);
 3     
 4     memset(a, 0, sizeof a), a[0] = 1;
 5     for (int i = 1; i <= n; i++) {
 6         for (int j = n; j >= 0; j--) {
 7             a[j+1] = (a[j+1] + a[j]) % MOD;
 8             a[j] = -1LL * x[i] * a[j] % MOD;
 9         }
10     }
11     
12     for (int i = 1; i <= n; i++) {
13         memcpy(t, a, sizeof t), memset(b, 0, sizeof b);
14         for (int j = n; j >= 0; j--) {
15             b[j] = t[j+1];
16             t[j] = (t[j] + 1LL * b[j] * x[i]) % MOD;
17             t[j+1] = 0;
18         }
19         
20         int Mul = 1;
21         for (int j = 1; j <= n; j++) if (i != j)
22             Mul = 1LL * Mul * (x[i] - x[j]) % MOD;
23         Mul = 1LL * Inv(Mul) * y[i] % MOD;
24         
25         for (int j = 0; j <= n; j++) b[j] = 1LL * b[j] * Mul % MOD;
26         for (int j = 0; j <= n; j++) ans[j] = (ans[j] + b[j]) % MOD;
27     }
28 }

拉格朗日插值法