【洛谷P4781】【模板】拉格朗日插值

题目

题目链接:https://www.luogu.com.cn/problem/P4781
由小学知识可知 \(n\) 个点 \((x_i,y_i)\) 可以唯一地确定一个多项式 \(y = f(x)\)
现在,给定这 \(n\) 个点,请你确定这个多项式,并求出 \(f(k) \bmod 998244353\) 的值。
\(1 \le n \leq 2\times 10^3\)\(1 \le x_i,y_i,k < 998244353\)\(x_i\) 两两不同。

思路

给出一个 \(n\) 次多项式的点值,拉格朗日插值法可以在 \(O(n^2)\) 的时间内求出该多项式 \(f(k)\) 的值。
为了插出该多项式,拉格朗日插值的思路是对每一个点值构建一个拉格朗日基本多项式,使得将 \(x_1\sim x_n\) 带进去只有 \(x_i\) 的函数值是 \(1\),其余均为 \(0\)
先不考虑如何构建多项式使得只有 \(x_i\) 带进去非 \(0\)。因为 \(x_i\) 两两不等,所以可以考虑如下多项式

\[\prod_{j\neq i}(k-x_j) \]

显然只有当 \(k=x_i\) 的时候非 \(0\)。为了让其值为 \(1\),可以给每一项都除以 \(x_i-x_j\),此时再带入 \(k=x_i\) 多项式的值就是 \(1\cdot 1\cdot 1\cdots=1\)
所以说我们可以插出多项式

\[f(k)=\sum_{i=1}^{n}y_i\prod_{j\neq i}\frac{k-a_j}{x_i-x_j} \]

当我们带入 \(x_i\) 时,多项式的函数值就是 \(0+0+\cdots+y_i+0+0+\cdots\)。这样我们就插出这个多项式了。
时间复杂度 \(O(n^2)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=2010,MOD=998244353;
int n,k;
ll ans,x[N],y[N];

ll fpow(ll x,ll k)
{
	ll ans=1;
	for (;k;k>>=1,x=x*x%MOD)
		if (k&1) ans=ans*x%MOD;
	return ans;
}

int main()
{
	scanf("%d%d",&n,&k);
	for (int i=1;i<=n;i++)
		scanf("%lld%lld",&x[i],&y[i]);
	for (int i=1;i<=n;i++)
	{
		ll res1=1,res2=1;
		for (int j=1;j<=n;j++)
			if (i!=j)
			{
				res1=res1*(k-x[j])%MOD;
				res2=res2*(x[i]-x[j])%MOD;
			}
		ans=(ans+res1*fpow(res2,MOD-2)%MOD*y[i])%MOD;
	}
	printf("%lld",(ans%MOD+MOD)%MOD);
	return 0;
}
posted @ 2021-02-16 15:27  stoorz  阅读(40)  评论(0编辑  收藏  举报