Chgtaxihe's blog Chgtaxihe's blog
首页
练习
算法学习
读书笔记
小玩意

Chgtaxihe

首页
练习
算法学习
读书笔记
小玩意
  • 数论

    • 一些小问题
    • 二次剩余学习笔记
    • 卡特兰数学习笔记
    • 同余最短路学习笔记
    • 康托展开学习笔记
    • 快速傅里叶变换学习笔记
    • 拉格朗日插值学习笔记
      • 重心拉格朗日插值法
    • 拓展欧几里得学习笔记
    • 斐波那契数列学习笔记
    • 斯特林数笔记
    • 本原勾股数组学习笔记
    • 模运算学习笔记
    • 欧拉函数
    • 类欧几里得学习笔记
    • 素性检测与大数分解
    • 素数计数问题
    • 组合数问题
    • 高斯整数学习笔记
  • 动态规划

  • 暴力

  • 图论

  • 数据结构

  • 字符串

  • 几何

  • 博弈论

  • 其他

拉格朗日插值学习笔记

# 前言

学FFT的时候碰到了这个神奇的东西,于是记录一下。

# 拉格朗日插值法

可知由n+1n+1n+1个不同xxx坐标的点可以为以确定一个最高次数为nnn的多项式。

那么给定这f(x)f(x)f(x)对应的n+1n+1n+1个点,并求f(a)f(a)f(a)

拉格朗日插值法可以在O(n2)O(n^2)O(n2)复杂度内解决问题(当然也可以用高斯消元O(n3)O(n^3)O(n3)解决)

# 模板题 洛谷 P4781

给定(x0,y0),...,(xk,yk)(x_0,y_0),...,(x_k,y_k)(x0​,y0​),...,(xk​,yk​),求f(x)f(x)f(x),结果对998244353998244353998244353取余

假设任意两个xi,xj(i≠j)x_i,x_j(i\ne j)xi​,xj​(i=j)都不相同,那么应用拉格朗日插值公式得到的插值多项式为:

L(x)=∑j=0kyjlj(x)L(x)=\sum_{j=0}^k y_jl_j(x)L(x)=∑j=0k​yj​lj​(x)

其中lj(x)l_j(x)lj​(x)为拉格朗日基本多项式,表达式为

lj(x)=∏i=0,i≠jkx−xixj−xil_j(x)=\prod_{i=0,i\ne j}^k \frac{x-x_i}{x_j-x_i}lj​(x)=∏i=0,i=jk​xj​−xi​x−xi​​

其特点是在xjx_jxj​上取值为1,其他点xix_ixi​上取值为0

#include <bits/stdc++.h>
#define ll long long

using namespace std;
const int maxn = 2e3 + 1000;
const ll mod = 998244353;

ll n, k;
ll x[maxn], y[maxn]; 

ll inv(ll val){
    ll ret = 1, t = mod-2;
    while(t){
        if(t & 1) ret = ret * val % mod;
        t >>= 1;
        val = val * val % mod;
    }
    return ret;
}

signed main(){
    cin >> n >> k;
    for(int i=0; i<n; i++) cin >> x[i] >> y[i];
    ll ans = 0, t1, t2;
    for(int i=0; i<n; i++){
        t1 = t2 = 1;
        for(int j=0; j<n; j++){
            if(j == i) continue;
            t1 = t1 * ((x[i] - x[j] + mod) % mod) % mod;
            t2 = t2 * ((k - x[j] + mod) % mod) % mod;
        }
        ans += y[i] * t2 % mod * inv(t1) % mod;
        ans %= mod;
    }
    cout << ans << '\n';
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 重心拉格朗日插值法

可以发现,每当我们添加一个新点,在上述方法中就得完全重新计算。

下面是拉格朗日插值法的一种改进。

令l(x)=(x−x0)(x−x1)...(x−xk)l(x)=(x-x_0)(x-x_1)...(x-x_k)l(x)=(x−x0​)(x−x1​)...(x−xk​)

则lj(x)=l(x)x−xj1∏i=0,i≠jk(xj−xi)l_j(x)=\frac{l(x)}{x-x_j}\frac{1}{\prod_{i=0,i\ne j}^k(x_j-x_i)}lj​(x)=x−xj​l(x)​∏i=0,i=jk​(xj​−xi​)1​

定义重心权

wj=1∏i=0,i≠jk(xj−xi)w_j=\frac{1}{\prod_{i=0,i\ne j}^k(x_j-x_i)}wj​=∏i=0,i=jk​(xj​−xi​)1​

则lj(x)=l(x)wjx−xjl_j(x)=l(x)\frac{w_j}{x-x_j}lj​(x)=l(x)x−xj​wj​​

拉格朗日插值多项式变为L(x)=l(x)∑j=0kyjwjx−xjL(x)=l(x)\sum_{j=0}^k y_j\frac{w_j}{x-x_j}L(x)=l(x)∑j=0k​yj​x−xj​wj​​

每当插入一个点(xk+1,yk+1)(x_{k+1},y_{k+1})(xk+1​,yk+1​),则只需对每个wiw_iwi​除以xi−xk+1x_i-x_{k+1}xi​−xk+1​即可得到新的重心权

重新计算的复杂度为O(n)O(n)O(n)

# 参考资料

维基百科-拉格朗日插值法 (opens new window)

上次更新: 2021/02/24, 03:37:30
快速傅里叶变换学习笔记
拓展欧几里得学习笔记

← 快速傅里叶变换学习笔记 拓展欧几里得学习笔记→

最近更新
01
深入理解Java虚拟机
03-04
02
DNS工作原理
02-27
03
改用VuePress啦
02-23
更多文章>
Theme by Vdoing | Copyright © 2019-2021
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式