【模板】拉格朗日插值
由小学知识可知n个点\((x_i,y_i)\)可以唯一地确定一个多项式\(y=f(x)\)。
那么问题来了,既然这是小学的知识,那么为什么我这个初一的蒟蒻看到这玩意还是一脸懵呢
引入正题:我们改怎么求出这个多项式呢?
当然是用拉格朗日插值来求解啊,不然这题怎么叫“拉格朗日插值”的模板呢 滑稽滑稽
那么插值又是什么东东呢?
简单来讲,就是:
在离散数据的基础上补插连续函数,
使得这条连续曲线通过全部给定的离散数据点。
插值是离散函数逼近的重要方法,
利用它可通过函数在有限个点处的取值状况,
估算出函数在其他点处的近似值。
插值就是用来填充图像变换时像素之间的空隙。
——百度百科
好吧我也不懂
本蒟蒻只会拉格朗日插值,其他的一窍不通……
那么就先来讲拉格朗日插值法:
在数值分析中,
拉格朗日插值法是以法国十八世纪数学家约瑟夫·拉格朗日命名的一种多项式插值方法。
许多实际问题中都用函数来表示某种内在联系或规律,
而不少函数都只能通过实验和观测来了解。
如对实践中的某个物理量进行观测,
在若干个不同的地方得到相应的观测值,
拉格朗日插值法可以找到一个多项式,
其恰好在各个观测的点取到观测到的值。
这样的多项式称为拉格朗日(插值)多项式。
数学上来说,
拉格朗日插值法可以给出一个恰好穿过二维平面上若干个已知点的多项式函数。
——百度百科
然后是拉格朗日插值的历史(历史也是很重要滴):
拉格朗日插值法最早被英国数学家爱德华·华林于1779年发现。
不久后(1783年)由莱昂哈德·欧拉再次发现。
1795年,拉格朗日在其著作《师范学校数学基础教程》中发表了这个插值方法,从此他的名字就和这个方法联系在一起。
——百度百科
所以各位小伙伴记住啦,拉格朗日插值并不是拉格朗日发明的哦
瞎扯完了,我们来写程序。
写程序之前,先来搞搞公式。
由百度优先搜索算法可得,拉格朗日插值的公式为:
\[f(k)=\sum\limits_{i=1}^n(y_i \prod\limits_{i\ne j}^n\dfrac{k-x_j}{x_i-x_j})
\]
很好,有了公式我们就可以瞎搞了哈哈哈
那么问题来了,怎么求那个奇奇怪怪的\(\prod\limits_{i\ne j}^n\frac{k-x_j}{x_i-x_j}\)呢?
如果您直接打暴力而且A掉的话,那么请收下我的膝盖,因为我这么干从来就没A过。
PS:上次我有个同学用\(O(2^n)\)的算法+剪枝过了\(n=50\)的数据,这就是Oier们的优良传统
经过一番思维挣扎后,我想到了乘法逆元。
如果您不知道乘法逆元是个什么东西,请自行查找这里
然后这个除法就愉快地变成了乘法
下面给出模拟的程序:
#include <bits/stdc++.h>
using namespace std;
const long long Mo=998244353;
long long Fast_power(long long n,long long m,long long p)
//我不知道这个Fast_power英语语法上对不对,好多大佬都是写成Quick_pow的,照理来说两个都是adj.,应该都没问题
{
long long r=1;
while(m)
{
if(m%2==1) r=r*n%p;
n=n*n%p;
m/=2;
}
return r;
}//快速幂
long long x[10000],y[10000],n,k,ans=0;
int main()
{
cin>>n>>k;
for(int i=1; i<=n; i++) cin>>x[i]>>y[i];
for(int i=1; i<=n; i++)
{
long long s1=y[i]%Mo;//这里直接先把那个在外面的yi乘进去
long long s2=1;
for(int j=1; j<=n; j++)//去求那个∏,各位大佬一定都看得懂模拟的出来
if(i!=j)
{
s1=s1*(k-x[j])%Mo;//分子
s2=s2*((x[i]-x[j])%Mo)%Mo;//分母
}
ans+=s1*Fast_power(s2,Mo-2,Mo)%Mo;
/*
乘法逆元的用场,
Fast_power(s2,Mo-2,Mo)是s2在mod Mo意义下的乘法逆元,
这里比较实用的是快速幂,
但是在乘法逆元的板子题那里,
快速幂会一败T地
*/
ans=(ans+Mo)%Mo;
}
cout<<ans;
return 0;
}
到此这道题就AC了,QAQ