loj 165

题目描述
这是一道模板题。

维护一个点集 S,初始时点集为空集。下面依次进行 n 个操作,操作有两种:

1 x y:向点集中添加点\((x,y)\)。保证点集中 x 互不相同。
2 k:输出 \(f(k) mod 998244353\) 的值,其中 \(f(x)\) 是一个次数不超过 \(|s|-1\) 次的函数,且经过 s 中所有的点。
输入格式
第一行,一个整数 n,表示操作个数。

接下来 n 行,每行 2 或 3 个整数,描述操作。

数据保证第一个操作必定为 1 类型操作。

输出格式
多行,第 i 行,一个整数,表示对第 i 个 2 类型操作要求计算的 \(f(k) mod 998244353\) 的值。

样例
输入
6
1 2 3
2 5
1 4 7
2 5
1 1 4
2 5
输出
3
9
12

数据范围与提示
对于 \(100 \%\) 的数据,$ 1<=n<=3000,1<=x,y,k<998244353$,所有x 互不相同。

数据有一定梯度。


据说叫做重心拉格朗日差值
通过对原公式进行变形,使得拉格朗日插值法能够进行增加点和随时计算值。

\[y=\sum_{i=1}^{n}y_i\prod_{j=1,j\neq i}^{n}(x-x_j)/(x_i-x_j) \]

\[y=\sum_{i=1}^{n}y_i\frac{\prod_{j=1,j\neq i}^{n}(x-x_j)}{\prod_{j=1,j\neq i}^{n}(x_i-x_j)} \]

\[y=\sum_{i=1}^{n}y_i\frac{\prod_{j=1}^{n}(x-x_j)}{(x-x_i)\prod_{j=1,j\neq i}^{n}(x_i-x_j)} \]

\[y=\prod_{j=1}^{n}(x-x_j)\sum_{i=1}^{n}\frac{y_i}{(x-x_i)\prod_{j=1,j\neq i}^{n}(x_i-x_j)} \]

这里面,\(\prod_{j=1}^{n}(x-x_j)\)部分每次询问时可以\(O(n)\)得到。
\(y_i\)\(x-x_i\)可以\(O(1)\)得到
\(\prod_{j=1,j\neq i}^{n}(x_i-x_j)\)则需要一个数组来进行存储,每次增加点都要\(O(n)\)维护(代码中lc[])。


#include<bits/stdc++.h>
using namespace std;
const int maxn=3010;
const int mod=998244353;
typedef long long ll;
ll lc[maxn],x[maxn],y[maxn];
int nn,n;
ll qpow(int x,int y)
{
	if(y==0)return 1;
	ll tp=qpow(x,y/2);
	tp=tp*tp%mod;
	if(y&1)tp=tp*x%mod;
	return tp;
}
int main()
{
	scanf("%d",&nn);
	while(nn--)
	{
		int op,a,b;
		scanf("%d",&op);
		if(op==1)
		{
			scanf("%d%d",&a,&b);
			++n;
			y[n]=b;x[n]=a;
			lc[n]=1;
			for(int i=1;i<n;++i)lc[i]=lc[i]*(x[i]-x[n])%mod;
			for(int i=1;i<n;++i)lc[n]=lc[n]*(x[n]-x[i])%mod;
		}
		else 
		{
			scanf("%d",&a);
			bool fd=0;
			for(int i=1;i<=n;++i)
				if(x[i]==a)
				{
					printf("%d\n",y[i]);
					fd=1;
				}
			if(fd==1)continue;
			ll tq=1;
			for(int i=1;i<=n;++i)tq=tq*(a-x[i])%mod;
			ll he=0;
			for(int i=1;i<=n;++i)he=(he+y[i]*qpow(lc[i],mod-2)%mod*qpow(a-x[i],mod-2)%mod)%mod;
			printf("%lld\n",(tq*he%mod+mod)%mod);
		}
	}
	return 0;
}

posted on 2021-07-12 22:27  gryzy  阅读(85)  评论(0编辑  收藏  举报

导航