拉格朗日插值法

模板题
给出 n n n个点 ( x i , y i ) (x_i,y_i) (xi,yi),让你确定这个 n − 1 n-1 n1次方程并代入求值

这个有三种求法
第一种是差分法,只适用于 x i = i x_i=i xi=i的情况,就是不断做差分直到序列变成一个定值就可以求出所有项的系数,复杂度 O ( n 2 ) O(n^2) O(n2)

第二种是高斯消元法,形如 f ( x ) = ∑ i = 1 n a i × x i f(x)=\sum_{i=1}^na_i\times x^i f(x)=i=1nai×xi
n n n x i x_i xi代入得到 n n n n n n元一次方程高斯消元求解,复杂度 O ( n 3 ) O(n^3) O(n3)

第三种就是拉格朗日插值法
拉格朗日基本多项式为:
l i ( x ) = ∏ j = 0 , j ≠ i n x − x j x i − x j l_i(x)=∏_{j=0,j\neq i}^n\frac{x-x_j}{x_i-x_j} li(x)=j=0,j̸=inxixjxxj
可以发现 l i ( x i ) = 1 l_i(x_i)=1 li(xi)=1,其余都是 0 0 0,那么就可以构造出这个多项式:
f ( x ) = ∑ i = 1 n y i × l i ( x ) f(x)=\sum_{i=1}^ny_i\times l_i(x) f(x)=i=1nyi×li(x),根据性质 f ( x i ) = y i f(x_i)=y_i f(xi)=yi也就是经过了这 n n n个点,这样用多项式乘除法就可以 O ( n 2 ) O(n^2) O(n2)求出多项式系数,带入求值也可以 O ( n 2 ) O(n^2) O(n2),注意求值时不用每次乘逆元,只要先把分子分母分开算最后再乘一次就好了。

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 2005
#define LL long long
using namespace std;
const int mod=998244353;

inline int rd(){
	int x=0,f=1;char c=' ';
	while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
	while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
	return x*f; 
}

int n,K,x[maxn],y[maxn];
LL ans;

inline int qpow(int x,int k){
	int ret=1;
	while(k){
		if(k&1) ret=1LL*ret*x%mod;
		x=1LL*x*x%mod; k>>=1;
	} return ret%mod;
}

int main(){
	n=rd(); K=rd();
	for(int i=1;i<=n;i++) x[i]=rd(),y[i]=rd();
	for(int i=1;i<=n;i++){
		LL fz=y[i]%mod,fm=1;
		for(int j=1;j<=n;j++)
			if(j!=i) 
				fz=1LL*fz*(K-x[j]+mod)%mod,fm=1LL*fm*(x[i]-x[j]+mod)%mod;
		(ans+=1LL*fz*qpow(fm,mod-2)%mod)%=mod;
	}
	printf("%lld\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值