拉格朗日插值
其实很简单。
考虑一个 \(k\) 次多项式,需要 \(k+1\) 个 \(x\) 值不同的点来确定。那现在要求构造一个函数 $f(x) $ 过点 \(P_1(x_1,y_1),P_2(x_2,y_2),\cdots ,P_n(x_n,y_n)\)。我们设第 \(i\) 个点在 \(x\) 轴的投影是 \(P_i'(x_i,0)\)。
考虑构造 \(n\) 个函数 \(g_i(x)\),使得对于函数 \(g_i(x)\),过 \(P_j'(x_j,y_j),j\neq i\) 和 \(P_i(x_i,y_i)\)。即只在 \((x_{i-1},x_{i+1})\) 区间有实际值。
那么可知,\(\displaystyle f(x)=\sum_{i=1}^n g_i(x)\)。既然让 \(\forall j\neq i\) 都没值,那就设 \(\displaystyle g_i(x)=a\prod_{j\neq i} (x-x_j)\),其中 \(a\) 是修正量,因为要满足 \(g_i(x_i)=y_i\)。
带入 \(P_i(x_i,y_i)\) 可得:
带回 \(g_i(x)\) 可得:
带回 \(f(x)\) 可得:
然后这就是拉格朗日插值的形式。整体算的时间复杂度是 \(O(n^2)\)。
模板代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e3+3,mod=998244353;
int ppow(int a,int b)
{
int res=1;
while(b)
{
if(b&1) res=(res*a)%mod;
a=(a*a)%mod,b>>=1;
}return res;
}
int n,k;
int x[N],y[N];
signed main()
{
cin>>n>>k;
int ans=0;
for(int i=1;i<=n;i++) cin>>x[i]>>y[i];
for(int i=1;i<=n;i++)
{
int res1=1,res2=1;
for(int j=1;j<=n;j++)
{
if(i==j) continue;
res1=(res1*(k-x[j]+mod)%mod)%mod;
res2=(res2*(x[i]-x[j]+mod)%mod)%mod;
}
ans=(ans+y[i]*res1%mod*ppow(res2,mod-2)%mod)%mod;
}
cout<<ans;
}
然后有一个比较神秘的问题,是说 \(\displaystyle\sum_{i=1}^{n}{i^k}\) 是一个 \(k+1\) 次多项式。
试着证明一下:
若它是一个 \(k+1\) 次多项式,那么它一定和另一个 \(k+1\) 次多项式有对等关系。我们将 \(\sum_{i=1}^{n}{i^k}\) 记为 \(S(n,k)\)。
考虑将两个 \(k+1\) 次多项式 \((n+1)^{k+1}\) 和 \(n^{k+1}\) 相减,可以得出:
然后,将 \(n^{k+1}\) 和 \((n-1)^{k+1}\) 相减,可以得出:
以此类推,到最后,令 \(1^{k+1}\) 和 \(0^{k+1}\) 相减,是 \(\displaystyle \sum_{i=0}^k 0^i\cdots \cdots \cdots (n+1)\)
这样,我们就有了 \(n+1\) 个式子,考虑将他们加起来,根据裂项相消法,\(\displaystyle\sum_{i=1}^{n+1}(i)=(n+1)^{k+1}\)。
另一侧:
由此,不难得到 \(S(n,i)\) 和 \((n+1)^{k+1}\) 的关系,也就证明了这个结论。