拉格朗日插值学习笔记

P4781 【模板】拉格朗日插值

方法 3:拉格朗日插值法

根据多项式除法那么我们会有:

f ( x ) ≡ f ( a ) ( m o d ( x − a ) ) f(x)\equiv f(a)\pmod{(x-a)} f(x)f(a)(mod(xa))

这是显然的,因为 f ( x ) − f ( a ) = ( a 0 − a 0 ) + a 1 ( x 1 − a 1 ) + a 1 ( x 2 − a 2 ) + ⋯ + a n ( x n − a n ) f(x)-f(a)=(a_0-a_0)+a_1(x^1-a^1)+a_1(x^2-a^2)+\cdots +a_n(x^n-a^n) f(x)f(a)=(a0a0)+a1(x1a1)+a1(x2a2)++an(xnan),这个式子显然有 ( x − a ) (x-a) (xa) 这个因式,所以得证。

这样我们就可以列一个关于 f ( x ) f(x) f(x) 的多项式线性同余方程组:

{ f ( x ) ≡ y 1 ( m o d ( x − x 1 ) ) f ( x ) ≡ y n ( m o d ( x − x 2 ) ) ⋯ 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_n\pmod{(x-x_2)}\\ \cdots\\ f(x)\equiv y_n\pmod{(x-x_n)} \end{cases} f(x)y1(mod(xx1))f(x)yn(mod(xx2))f(x)yn(mod(xxn))

我们根据中国剩余定理,有:

M = ∏ i = 1 n ( x − x i ) , m i = M x − x i = ∏ j ≠ i ( x − x j ) M=\prod_{i=1}^n{(x-x_i)},m_i=\dfrac M{x-x_i}=\prod_{j\ne i}{(x-x_j)} M=i=1n(xxi),mi=xxiM=j=i(xxj)

m i m_i mi ( x − x i ) (x-x_i) (xxi) 意义下的逆元就是:

m i − 1 = ∏ j ≠ i 1 x i − x j m_i^{-1}=\prod_{j\ne i}{\dfrac 1{x_i-x_j}} mi1=j=ixixj1

所以就有:

f ( x ) ≡ ∑ i = 1 n y i m i m i − 1 ≡ ∑ i = 1 n y i ∏ j ≠ i x − x j x i − x j ( m o d M ) f(x)\equiv\sum_{i=1}^n{y_im_im_i^{-1}}\equiv\sum_{i=1}^n{y_i\prod_{j\ne i}{\dfrac {x-x_j}{x_i-x_j}}}\pmod M f(x)i=1nyimimi1i=1nyij=ixixjxxj(modM)

所以在模意义下 f ( x ) f(x) f(x) 就是唯一的,即:

f ( x ) = ∑ i = 1 n y i ∏ j ≠ i x − x j x i − x j f(x)=\sum_{i=1}^n{y_i\prod_{j\ne i}{\dfrac {x-x_j}{x_i-x_j}}} f(x)=i=1nyij=ixixjxxj

这就是拉格朗日插值的表达式。

如果要将每一项的系数都算出来,时间复杂度仍为 O ( n 2 ) O(n^2) O(n2),但是本题中只用求出 f ( k ) f(k) f(k) 的值,所以在计算上式的过程中直接将 k k k 代入即可。

f ( k ) = ∑ i = 1 n y i ∏ j ≠ i k − x j x i − x j f(k)=\sum_{i=1}^{n} y_i\prod_{j\neq i }\frac{k-x_j}{x_i-x_j} f(k)=i=1nyij=ixixjkxj

本题中,还需要求解逆元。如果先分别计算出分子和分母,再将分子乘进分母的逆元,累加进最后的答案,时间复杂度的瓶颈就不会在求逆元上,时间复杂度为 O ( n 2 ) O(n^2) O(n2)

代码实现

#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
template<class...Args>
void debug(Args... args) {//Parameter pack
	auto tmp = { (cout << args << ' ', 0)... };
	cout << "\n";
}
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>pll;
typedef pair<int, int>pii;
const ll N = 1e5 + 5;
const ll INF = 0x7fffffff;
const ll MOD = 1e9 + 7;

ll qpow(ll x, ll n, ll mod) {
	ll ans = 1;
	while (n) {
		if (n & 1)ans = (ans * x) % mod;
		x = (x * x) % mod;
		n >>= 1;
	}
	return ans % mod;
}
ll get_inv(ll num,ll mod) {
	return qpow(num, mod - 2, mod);
}
ll lagrange(vector<ll> x,vector<ll> y,int k ,int mod) {
	int n = x.size();
	ll ans = 0;
	ll s1, s2;
	for (int i = 0; i < n; i++) {
		s1 = y[i] % mod;
		s2 = 1;
		for (int j = 0; j < n; j++) {
			if (i != j) {
				s1 = s1 * (k - x[j]) % mod;
				s2 = s2 * ((x[i] - x[j] % mod) % mod) % mod;
			}
		}
		ans += s1 * get_inv(s2, mod) % mod;
		ans = (ans + mod) % mod;
	}
	return ans;
}
int main() {
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);

	int n, k;
	cin >> n >> k;
	vector<ll>x(n),y(n);
	for (int i = 0; i < n; i++) cin >> x[i] >> y[i];
	cout << lagrange(x,y,k, 998244353);

	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值