1. 程式人生 > 實用技巧 >LOJ #165. 拉格朗日插值

LOJ #165. 拉格朗日插值

重心拉格朗日插值模板題。

用上面那篇文章的公式計算。插入時更新每個 \(w_i\),詢問時分別 \(O(n)\) 計算 \(l(k)\)\(\sum\limits_{i=1}^n \frac{w_i}{k-x_i}\) 即可。注意使用上述公式時 \(k-x_i\) 不能為 \(0\),所以我們要特判 \(k=x_i\) 的情況。

程式碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define int long long

using namespace std;

const int N=3009,M=998244353;
int n,cnt,x[N],y[N],w[N];

void init()
{
	scanf("%lld",&n);
}

int ksm(int a,int b)
{
	int res=1;
	while(b)
	{
		if(b&1)
			res=res*a%M;
		b>>=1,a=a*a%M;
	}
	return res;
}

void work()
{
	int opt,X,Y;
	while(n--)
	{
		scanf("%lld",&opt);
		if(opt==1)
		{
			scanf("%lld %lld",&X,&Y);
			x[++cnt]=X,y[cnt]=w[cnt]=Y;
			for (int i=1;i<cnt;i++)
				w[i]=w[i]*ksm(x[i]-x[cnt],M-2)%M,
				w[cnt]=w[cnt]*ksm(x[cnt]-x[i],M-2)%M;
		}
		else
		{
			scanf("%lld",&X);
			int flag=0;
			for (int i=1;i<=cnt;i++)
				if(X==x[i])
				{
					flag=1,printf("%lld\n",y[i]);
					break;
				}
			if(flag) continue;
			int tmp=1,_tmp=0;
			for (int i=1;i<=cnt;i++)
				tmp=tmp*(X-x[i])%M;
			for (int i=1;i<=cnt;i++)
				_tmp=(_tmp+w[i]*ksm(X-x[i],M-2)%M)%M;
			printf("%lld\n",(tmp*_tmp%M+M)%M);
		}
	}
}

signed main()
{
	init();
	work();
	return 0;
}