Luogu4238 【模板】多项式求逆(NTT)

时间:2020-12-14 07:36:50

  http://blog.miskcoo.com/2015/05/polynomial-inverse 好神啊!

  B(x)=B'(x)·(2-A(x)B'(x))

  注意ntt的时候防止项数溢出,即将多项式补零成n位后,相乘时次数最高的非零项不超过n次。

  upd:可以在点值表示下直接相乘。又好写又跑得快。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 550000
#define P 998244353
int n,t,r[N],a[N],b[N],c[N],d[N];
int ksm(int a,int k)
{
if (k==) return ;
int tmp=ksm(a,k>>);
if (k&) return 1ll*tmp*tmp%P*a%P;
else return 1ll*tmp*tmp%P;
}
int inv(int x){return ksm(x,P-);}
void DFT(int n,int *a,int p)
{
for (int i=;i<n;i++) if (i<r[i]) swap(a[i],a[r[i]]);
for (int i=;i<=n;i<<=)
{
int wn=ksm(p,(P-)/i);
for (int j=;j<n;j+=i)
{
int w=;
for (int k=j;k<j+(i>>);k++,w=1ll*w*wn%P)
{
int x=a[k],y=1ll*w*a[k+(i>>)]%P;
a[k]=(x+y)%P,a[k+(i>>)]=(x-y+P)%P;
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("inverse.in","r",stdin);
freopen("inverse.out","w",stdout);
const char LL[]="%I64d";
#else
const char LL[]="%lld";
#endif
n=read();
for (int i=;i<n;i++) a[i]=read();
t=;b[]=inv(a[]);
int inv3=inv();
while (t<n)
{
t<<=;
for (int i=;i<t;i++) d[i]=a[i];
t<<=;
memcpy(c,b,sizeof(b));
for (int i=;i<t;i++) r[i]=(r[i>>]>>)|(i&)*(t>>);
DFT(t,c,);DFT(t,d,);
for (int i=;i<t;i++) c[i]=1ll*c[i]*d[i]%P;
DFT(t,c,inv3);
int invt=inv(t);
for (int i=;i<t;i++) c[i]=1ll*c[i]*invt%P;
for (int i=;i<t;i++) c[i]=(P-c[i])%P;
c[]=(c[]+)%P;
for (int i=(t>>);i<t;i++) c[i]=;
DFT(t,b,);DFT(t,c,);
for (int i=;i<t;i++) b[i]=1ll*b[i]*c[i]%P;
DFT(t,b,inv3);
for (int i=;i<t;i++) b[i]=1ll*b[i]*invt%P;
for (int i=(t>>);i<t;i++) b[i]=;
t>>=;
}
for (int i=;i<n;i++) printf("%d ",b[i]);
return ;
}