模板题
给出
n
n
n个点
(
x
i
,
y
i
)
(x_i,y_i)
(xi,yi),让你确定这个
n
−
1
n-1
n−1次方程并代入求值
这个有三种求法
第一种是差分法,只适用于
x
i
=
i
x_i=i
xi=i的情况,就是不断做差分直到序列变成一个定值就可以求出所有项的系数,复杂度
O
(
n
2
)
O(n^2)
O(n2)
第二种是高斯消元法,形如
f
(
x
)
=
∑
i
=
1
n
a
i
×
x
i
f(x)=\sum_{i=1}^na_i\times x^i
f(x)=∑i=1nai×xi
将
n
n
n个
x
i
x_i
xi代入得到
n
n
n个
n
n
n元一次方程高斯消元求解,复杂度
O
(
n
3
)
O(n^3)
O(n3)
第三种就是拉格朗日插值法
拉格朗日基本多项式为:
l
i
(
x
)
=
∏
j
=
0
,
j
≠
i
n
x
−
x
j
x
i
−
x
j
l_i(x)=∏_{j=0,j\neq i}^n\frac{x-x_j}{x_i-x_j}
li(x)=∏j=0,j̸=inxi−xjx−xj
可以发现
l
i
(
x
i
)
=
1
l_i(x_i)=1
li(xi)=1,其余都是
0
0
0,那么就可以构造出这个多项式:
f
(
x
)
=
∑
i
=
1
n
y
i
×
l
i
(
x
)
f(x)=\sum_{i=1}^ny_i\times l_i(x)
f(x)=∑i=1nyi×li(x),根据性质
f
(
x
i
)
=
y
i
f(x_i)=y_i
f(xi)=yi也就是经过了这
n
n
n个点,这样用多项式乘除法就可以
O
(
n
2
)
O(n^2)
O(n2)求出多项式系数,带入求值也可以
O
(
n
2
)
O(n^2)
O(n2),注意求值时不用每次乘逆元,只要先把分子分母分开算最后再乘一次就好了。
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 2005
#define LL long long
using namespace std;
const int mod=998244353;
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
int n,K,x[maxn],y[maxn];
LL ans;
inline int qpow(int x,int k){
int ret=1;
while(k){
if(k&1) ret=1LL*ret*x%mod;
x=1LL*x*x%mod; k>>=1;
} return ret%mod;
}
int main(){
n=rd(); K=rd();
for(int i=1;i<=n;i++) x[i]=rd(),y[i]=rd();
for(int i=1;i<=n;i++){
LL fz=y[i]%mod,fm=1;
for(int j=1;j<=n;j++)
if(j!=i)
fz=1LL*fz*(K-x[j]+mod)%mod,fm=1LL*fm*(x[i]-x[j]+mod)%mod;
(ans+=1LL*fz*qpow(fm,mod-2)%mod)%=mod;
}
printf("%lld\n",ans);
return 0;
}