题解 P5667 【拉格朗日插值2】
可能更好的体验
本题可以将点值转化为下降幂系数,然后做一次下降幂多项式平移,再转化为点值。
关于如何将点值与下降幂系数互相转化,详见下降幂多项式乘法的模板。
这里主要讨论下降幂多项式的平移。
这里的平移指的是,已知多项式
这里需要用到下降幂的二项式定理。
《具体数学》习题5.37
考虑我们当前得到 ,对
观察这个式子 ,这是可以用一次多项式乘法得到的。
令
那么
得到
总共需要三次多项式乘法。
时间复杂度
Code:
#include<iostream>
#include<algorithm>
using namespace std;
const int N=524288,md=998244353,g3=(md+1)/3;
typedef long long LL;
int a[N],n,rev[N],lim,m,fac[N],iv[N],F[N];
inline void upd(int&a){a+=a>>31&md;}
inline int pow(int a,int b){
int ret=1;
for(;b;b>>=1,a=(LL)a*a%md)if(b&1)ret=(LL)ret*a%md;
return ret;
}
void init(int n){
int l=-1;
for(lim=1;lim<n;lim<<=1)++l;
for(int i=1;i<lim;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)<<l);
}
void FFT(int*a,int f){
for(int i=1;i<lim;++i)
if(i<rev[i])swap(a[i],a[rev[i]]);
for(int i=1;i<lim;i<<=1){
const int gi=pow(f?3:g3,(md-1)/(i<<1));
for(int j=0;j<lim;j+=i<<1)
for(int k=0,g=1;k<i;++k,g=(LL)g*gi%md){
const int x=a[j+k],y=a[j+k+i]*(LL)g%md;
upd(a[j+k]+=y-md),upd(a[j+k+i]=x-y);
}
}
if(!f){
const int vv=pow(lim,md-2);
for(int i=0;i<lim;++i)a[i]=(LL)a[i]*vv%md;
}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m;++n;
for(int i=0;i<n;++i)cin>>a[i];
for(int i=*fac=1;i<=n;++i)fac[i]=(LL)fac[i-1]*i%md;
iv[n]=pow(fac[n],md-2);
for(int i=n-1;~i;--i)iv[i]=(i+1LL)*iv[i+1]%md;
for(int i=0;i<n;++i)
a[i]=(LL)a[i]*iv[i]%md,F[i]=(i&1)?md-iv[i]:iv[i];
init(n<<1);
FFT(a,1),FFT(F,1);
for(int i=0;i<lim;++i)a[i]=(LL)a[i]*F[i]%md;
FFT(a,0);
for(int i=n;i<lim;++i)a[i]=F[i]=0;
F[0]=1;
for(int i=1;i<n;++i){
F[i]=(LL)F[i-1]*(m-i+1)%md;
a[i]=(LL)a[i]*fac[i]%md;
}
reverse(a,a+n);
for(int i=1;i<n;++i)
F[i]=(LL)F[i]*iv[i]%md;
FFT(a,1),FFT(F,1);
for(int i=0;i<lim;++i)a[i]=(LL)a[i]*F[i]%md;
FFT(a,0);
for(int i=n;i<lim;++i)a[i]=F[i]=0;
reverse(a,a+n);
for(int i=0;i<n;++i)F[i]=iv[i],a[i]=(LL)a[i]*iv[i]%md;
FFT(a,1),FFT(F,1);
for(int i=0;i<lim;++i)a[i]=(LL)a[i]*F[i]%md;
FFT(a,0);
for(int i=0;i<n;++i)
cout<<(LL)a[i]*fac[i]%md<<' ';
cout<<'\n';
return 0;
}