拉格朗日插值

概念

​ 对于一个 n 次多项式 F(x) ,我们给 n+1 个点的坐标 (xi,yi) 可以唯一确定这个多项式。如果直接暴力解方程组,用高斯消元时间复杂度是 O(n3) ,有时难以接受。所以我们引入拉格朗日插值算法。

​ 我们构造 F(x)=i=0n(yi×j=0jinxxjxixj) 。可以发现,对于点 (xp,yp) 来说,当 ipj 一定有一次会取到 p ,此时后面的式子值为 0 ;当 i=p 时,xxjxixj 值恒为 1 ,所以值为 yiyp ,所以有 F(xp)=yp 。所以 F(x) 为要求的多项式。如果要单点求 F(x) ,时间复杂度为 O(n2)


luogu P4781【模板】拉格朗日插值

​ 给定 n 个点,确定其多项式 F(x) ,求出F(k)mod998244353 的值 。1n2×103


模板题,代码如下

#include <iostream>
using namespace std;
const int N=2e3+9,mod=998244353;
typedef long long int ll;
int n,k,x[N],y[N];
ll ans;
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(c<'0' || c>'9') {if(c=='-') f=-1;c=getchar();}
	while(c>='0' && c<='9') {x=x*10+c-48,c=getchar();}
	return x*f;
}
ll quick_pow(ll x,int y)
{
	ll ans=1;
	while(y!=0)
	{
		if(y&1) ans=ans*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ans;
}
int main()
{
	n=read(),k=read();
	for(int i=1;i<=n;i++) x[i]=read(),y[i]=read();
	for(int i=1;i<=n;i++)
	{
		ll p=y[i],q=1;
		for(int j=1;j<=n;j++)
		{
			if(i==j) continue;
			p=p*(k-x[j])%mod,q=q*(x[i]-x[j])%mod;
		}
		ans=(ans+p*quick_pow(q,mod-2)%mod)%mod;
	}
	printf("%lld",(ans+mod)%mod);
	return 0;
}

CF622F The Sum of the k-th Powers

​ 给定 n,k ,求 i=1nikmod109+71n1090k106


比较经典的一道题,首先可以证明原式是一个 k+1 次多项式(证明较为复杂,此处略去)。我们设 F(x)=i=1xik ,我们要求的就是 F(n) 。考虑拉格朗日插值,这里要用到一个常用的套路,如果题目中没有给定这 k+2 个点,我们可以选取等差数列中连续的 k+2 个点。选等差数列有什么好处呢,对于等差数列 a ,我们令 an=a0+dn ,其中 d 为公差。我们将 (i,ai) 代入到拉格朗日插值的公式中,可以得到

F(x)=i=0n(yai×j=0jinxajd(ij)) 。具体地,我们假设 d=1 ,得到 F(x)=i=0n(yi×j=0jinxjij) 。我们继续化简,

j=0jin(ij)=i(i1)(i2)1(1)(2)(in+1)(in)

=i!×(ni)!×(1)ni

j=0jin(xj)=j=0i1(xj)×j=i+1n(xj)

所以我们只需要预处理阶乘的逆元以及 nj 的前缀积 pre 和后缀积 suf ,便可以 O(1) 求解后面的式子。然后我们再考虑 yi=F(i) ,我们可以先线性筛来预处理 ik ,然后再做一遍前缀和就可以得到所有的 yi 。所以总时间复杂度为 O(k)

事实上这个式子比较常用,所以建议记住解决方法。若所求的值可以 O(n),就直接线性筛加前缀和,否则就利用拉格朗日插值求值。

posted @   YC乌龙  阅读(86)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示