给定一个多项式
F
(
x
)
F(x)
F(x),请求出一个多项式
G
(
x
)
G(x)
G(x), 满足
F
(
x
)
∗
G
(
x
)
≡
1
(
m
o
d
x
n
)
F(x) * G(x) \equiv 1 ( mod\ x^n )
F(x)∗G(x)≡1(mod xn)
。系数对
998244353
998244353
998244353取模。
n
<
=
1
e
5
n<=1e5
n<=1e5
这个东西要用到一种叫多项式求逆的算法。我们设
f
(
x
)
f(x)
f(x)在模
x
⌈
n
2
⌉
x^{\lceil\frac{n}{2}\rceil}
x⌈2n⌉时的逆元是
g
(
x
)
g(x)
g(x),即
f
(
x
)
∗
g
(
x
)
=
1
(
m
o
d
x
⌈
n
2
⌉
)
f(x)*g(x)=1(mod\ x^{\lceil\frac{n}{2}\rceil})
f(x)∗g(x)=1(mod x⌈2n⌉),设我们要求的逆元是
f
′
(
x
)
f'(x)
f′(x)。那么根据取模的性质,有
f
(
x
)
∗
f
′
(
x
)
=
1
(
m
o
d
x
⌈
n
2
⌉
)
f(x)*f'(x)=1(mod\ x^{\lceil\frac{n}{2}\rceil})
f(x)∗f′(x)=1(mod x⌈2n⌉)。由此可得:
f
(
x
)
∗
(
f
′
(
x
)
−
g
(
x
)
)
=
0
(
m
o
d
x
⌈
n
2
⌉
)
f(x)*(f'(x)-g(x))=0(mod\ x^{\lceil\frac{n}{2}\rceil})
f(x)∗(f′(x)−g(x))=0(mod x⌈2n⌉) 由于
f
(
x
)
f(x)
f(x)不是
0
0
0,所以除掉
f
(
x
)
f(x)
f(x),得到:
(
f
′
(
x
)
−
g
(
x
)
)
=
0
(
m
o
d
x
⌈
n
2
⌉
)
(f'(x)-g(x))=0(mod\ x^{\lceil\frac{n}{2}\rceil})
(f′(x)−g(x))=0(mod x⌈2n⌉)
平方可得:
(
f
′
(
x
)
−
g
(
x
)
)
2
=
0
(
m
o
d
x
n
)
(f'(x)-g(x))^2=0(mod\ x^n)
(f′(x)−g(x))2=0(mod xn) 展开左边
f
′
(
x
)
2
−
2
∗
f
′
(
x
)
∗
g
(
x
)
+
g
(
x
)
2
=
0
(
m
o
d
x
n
)
f'(x)^2-2*f'(x)*g(x)+g(x)^2=0(mod\ x^n)
f′(x)2−2∗f′(x)∗g(x)+g(x)2=0(mod xn) 由于
f
′
(
x
)
f'(x)
f′(x)是
f
(
x
)
f(x)
f(x)的逆元,所以同乘一个
f
(
x
)
f(x)
f(x)可以化简:
f
′
(
x
)
2
∗
f
(
x
)
−
2
∗
f
′
(
x
)
∗
f
(
x
)
∗
g
(
x
)
+
g
(
x
)
2
∗
f
(
x
)
f'(x)^2*f(x)-2*f'(x)*f(x)*g(x)+g(x)^2*f(x)
f′(x)2∗f(x)−2∗f′(x)∗f(x)∗g(x)+g(x)2∗f(x)
f
′
(
x
)
−
2
g
(
x
)
+
f
(
x
)
∗
g
(
x
)
2
=
0
(
m
o
d
x
n
)
f'(x)-2g(x)+f(x)*g(x)^2=0(mod\ x^n)
f′(x)−2g(x)+f(x)∗g(x)2=0(mod xn) 移项可得:
f
′
(
x
)
=
2
g
(
x
)
−
f
(
x
)
∗
g
(
x
)
∗
g
(
x
)
f'(x)=2g(x)-f(x)*g(x)*g(x)
f′(x)=2g(x)−f(x)∗g(x)∗g(x) 这样我们就可以由一个指数是当前
n
n
n一半时的逆元推出当前模数指数是
n
n
n时的逆元了,相当于一个倍增的过程,而其中需要多项式乘法,这个要用NTT。
分析一波复杂度: T ( n ) = T ( n 2 ) + O ( n l o g n ) T(n)=T(\frac{n}{2})+O(nlogn) T(n)=T(2n)+O(nlogn),我们设 O ( n l o g n ) O(nlogn) O(nlogn)为 x x x,我们会发现这个过程中运算量是 x + x 2 + x 4 + . . . x+\frac{x}{2}+\frac{x}{4}+... x+2x+4x+...,这个东西是不超过 2 x 2x 2x的,也就是不超过 O ( 2 n l o g n ) O(2nlogn) O(2nlogn)的,所以总复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,l,rev[500010],ji;
const double pi=acos(-1);
const long long g=3,gi=332748118,mod=998244353;
long long a[500010],b[500010],x[500010],y[500010];
inline int read()
{
int x=0;
char s=getchar();
while(s>'9'||s<'0')
s=getchar();
while(s>='0'&&s<='9')
{
x=x*10+s-'0';
s=getchar();
}
return x;
}
inline long long ksm(long long x,long long y)
{
long long res=1;
while(y)
{
if(y&1)
res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}
inline void ntt(long long *a,int dft,int len)
{
m=len;
l=0;
for(len=1;len<m;len<<=1)
++l;
for(int i=0;i<len;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<len;++i)
{
if(i<rev[i])
swap(a[i],a[rev[i]]);
}
for(int i=1;i<len;i<<=1)
{
long long wn=ksm((dft==1?g:gi),(mod-1)/(i<<1));
for(int j=0,p=i<<1;j<len;j+=p)
{
long long w=1;
for(int k=0;k<i;++k)
{
long long xx=a[j+k],yy=w*a[i+j+k]%mod;
a[j+k]=(xx+yy)%mod;
a[i+j+k]=(xx-yy+mod)%mod;
w=w*wn%mod;
}
}
}
if(dft==-1)
{
long long ni=ksm(m,mod-2);
for(int i=0;i<len;++i)
a[i]=a[i]*ni%mod;
}
}
inline void inv(long long *a,long long *b,int len)
{
if(len==1)
{
b[0]=ksm(a[0],mod-2);
return;
}
inv(a,b,len>>1);
for(int i=0;i<len;++i)
{
x[i]=a[i];
y[i]=b[i];
}
ntt(x,1,len<<1);
ntt(y,1,len<<1);
for(int i=0;i<(len<<1);++i)
x[i]=x[i]*y[i]%mod*y[i]%mod;
ntt(x,-1,len<<1);
for(int i=0;i<len;++i)
b[i]=(b[i]*2%mod-x[i]+mod)%mod;
}
int main()
{
n=read();
ji=n;
for(int i=0;i<=n-1;++i)
a[i]=read()%mod;
for(n=1;n<ji;n<<=1);
inv(a,b,n);
for(int i=0;i<ji;++i)
printf("%lld ",b[i]);
printf("\n");
return 0;
}