拉格朗日插值

tech2024-10-31  19

拉格朗日插值

简要阐述

结论给定 n + 1 n + 1 n+1个点最多可以得到一个 n n n次多项式的表达式,并且 f ( x ) = ∑ i = 1 n y i ∏ j ∤ i x − x j x i − y j f(x) = \sum_{i = 1} ^{n} y_i \prod\limits_{j \nmid i}\frac{x - x_j}{x_i - y_j} f(x)=i=1nyijixiyjxxj我们随便往里带入一个 x i , y j x_i, y_j xi,yj可以得到等式是成立的,所以我们只要套模板即可求得某个函数的值。

特殊情况

x x x的取值是连续的,我们还可以得到一个更优的算法。

p r e [ i ] = ( x − x 1 ) ( x − x 2 ) ( x − x 3 ) … ( x − x i − 1 ) ( x − x i ) , s u c [ i ] = ( x − x i ) ( x − x i + 1 ) ( x − x i + 2 ) … ( x − x n − 1 ) ( x − x n ) pre[i] = (x - x_1)(x - x_2) (x - x_3) \dots(x - x_{i - 1})(x - x_i),suc[i] = (x - x_{i})(x - x_{i + 1})(x - x_{i + 2}) \dots (x - x_{n - 1})(x - x_{n}) pre[i]=(xx1)(xx2)(xx3)(xxi1)(xxi),suc[i]=(xxi)(xxi+1)(xxi+2)(xxn1)(xxn)

所以上面式子的分母可以写成 p r e [ i − 1 ] × s u c [ i + 1 ] pre[i - 1] \times suc[i + 1] pre[i1]×suc[i+1],同样的分子写成 ( − 1 ) n − i ( i − 1 ) ! ( n − i ) ! (-1) ^{n - i} (i - 1) !(n - i)! (1)ni(i1)!(ni)!,这个时候提前处理好阶乘逆元,前缀积,后缀积即可达到 O ( n ) O(n) O(n)来求解了。

两个模板题

P4781 【模板】拉格朗日插值

/* Author : lifehappy */ #pragma GCC optimize(2) #pragma GCC optimize(3) #include <bits/stdc++.h> using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const double eps = 1e-7; const int N = 2e3 + 10, mod = 998244353; ll x[N], y[N], ans, s1, s2, n, k; ll quick_pow(ll a, int n) { ll ans = 1; while(n) { if(n & 1) ans = ans * a % mod; a = a * a % mod; n >>= 1; } return ans; } ll inv(ll x) { return quick_pow(x, mod - 2); } int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); scanf("%lld %lld", &n, &k); for(int i = 1; i <= n; i++) { scanf("%lld %lld", &x[i], &y[i]); } for(int i = 1; i <= n; i++) { s1 = y[i], s2 = 1; for(int j = 1; j <= n; j++) { if(i == j) continue; s1 = (s1 * (k - x[j]) % mod + mod) % mod, s2 = (s2 * (x[i] - x[j]) % mod + mod) % mod; } ans = (ans + s1 * inv(s2) % mod) % mod; } printf("%lld\n", ans); return 0; }

∑ i = 1 n i k \sum\limits_{i = 1} ^{n} i ^ k i=1nik

/* Author : lifehappy */ #pragma GCC optimize(2) #pragma GCC optimize(3) #include <bits/stdc++.h> using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const double eps = 1e-7; const int N = 1e6 + 10, mod = 1e9 + 7; ll fac[N], pre[N], suc[N], inv[N], prime[N], sum[N], n, k, cnt; bool st[N]; ll quick_pow(ll a, int n) { ll ans = 1; while(n) { if(n & 1) ans = ans * a % mod; a = a * a % mod; n >>= 1; } return ans; } void init() { sum[1] = 1; for(int i = 2; i < N; i++) { if(!st[i]) { prime[cnt++] = i; sum[i] = quick_pow(i, k); } for(int j = 0; j < cnt && i * prime[j] < N; j++) { st[i * prime[j]] = 1; sum[i * prime[j]] = 1ll * sum[i] * sum[prime[j]] % mod; if(i % prime[j] == 0) break; } } fac[0] = inv[0] = 1; for(int i = 1; i < N; i++) { sum[i] = (sum[i] + sum[i - 1]) % mod; fac[i] = 1ll * fac[i - 1] * i % mod; } inv[N - 1] = quick_pow(fac[N - 1], mod - 2); for(int i = N - 2; i >= 1; i--) { inv[i] = 1ll * inv[i + 1] * (i + 1) % mod; } } ll solve(ll n, int k) { ll ans = 0; init(); pre[0] = suc[k + 3] = 1; for(int i = 1; i <= k + 2; i++) pre[i] = 1ll * pre[i - 1] * (n - i) % mod; for(int i = k + 2; i >= 1; i--) suc[i] = 1ll * suc[i + 1] * (n - i) % mod; for(int i = 1; i <= k + 2; i++) { ll a = 1ll * pre[i - 1] * suc[i + 1] % mod, b = 1ll * inv[i - 1] * inv[k + 2 - i] % mod; if((k + 2 - i) & 1) b *= -1; ans = ((ans + 1ll * sum[i] * a % mod * b % mod) % mod + mod) % mod; } return ans; } int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); scanf("%lld %lld", &n, &k); printf("%lld\n", solve(n, k)); return 0; }
最新回复(0)