其實很簡單。
考慮一個 \(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;
}
然後有一個比較神秘的問題,是說 \(\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\) 個式子,考慮將他們加起來,根據裂項相消法,\(\sum_{i=1}^{n+1}(i)=(n+1)^{k+1}\)。
另一側:
由此,不難得到 \(S(n,i)\) 和 \((n+1)^{k+1}\) 的關係,也就證明了這個結論。