题意:
给出
n
−
1
n-1
n−1次多项式
A
(
x
)
A(x)
A(x),求一个
 
m
o
d
 
 
x
n
\bmod{\:x^n}
modxn下的多项式
B
(
x
)
B(x)
B(x),满足
B
(
x
)
≡
e
A
(
x
)
B(x) \equiv e^{A(x)}
B(x)≡eA(x),系数对
999244353
999244353
999244353取模。
n
<
=
100000
n<=100000
n<=100000
题解:
一个前置知识特别多的题,要用到多项式对数函数、多项式求逆、NTT、多项式牛顿迭代、泰勒展开。
设
f
(
x
)
=
e
A
(
x
)
(
m
o
d
x
n
)
f(x)=e^{A(x)}(mod\ x^n)
f(x)=eA(x)(mod xn),那么两边同时取对数得
ln
f
(
x
)
=
A
(
x
)
\ln f(x)=A(x)
lnf(x)=A(x)。我们设
g
(
x
)
=
ln
f
(
x
)
−
A
(
x
)
=
0
g(x)=\ln f(x)-A(x)=0
g(x)=lnf(x)−A(x)=0,
n
=
1
n=1
n=1时,答案可以直接求出。我们假设已经求出了
f
0
(
x
)
=
e
A
(
x
)
(
m
o
d
x
⌈
n
2
⌉
)
f_0(x)=e^{A(x)}(mod\ x^{\lceil\frac{n}{2}\rceil})
f0(x)=eA(x)(mod x⌈2n⌉),那么考虑如何扩展到
f
(
x
)
=
e
A
(
x
)
(
m
o
d
x
n
)
f(x)=e^{A(x)}(mod\ x^n)
f(x)=eA(x)(mod xn)。我们把
g
(
f
(
x
)
)
g(f(x))
g(f(x))在
f
0
(
x
)
f_0(x)
f0(x)处泰勒展开,得
g
(
f
(
x
)
)
=
g
(
f
0
(
x
)
)
+
g
′
(
f
0
(
x
)
)
1
!
(
f
(
x
)
−
f
0
(
x
)
)
+
g
′
′
(
f
0
(
x
)
)
2
!
(
f
(
x
)
−
f
0
(
x
)
)
2
+
.
.
.
g(f(x))=g(f_0(x))+\frac{g'(f_0(x))}{1!}(f(x)-f_0(x))+\frac{g''(f_0(x))}{2!}(f(x)-f_0(x))^2+...
g(f(x))=g(f0(x))+1!g′(f0(x))(f(x)−f0(x))+2!g′′(f0(x))(f(x)−f0(x))2+...因为
ln
f
(
x
)
\ln f(x)
lnf(x)在模
x
n
x^n
xn意义下与
A
(
x
)
A(x)
A(x)相同,
x
n
x^n
xn是
x
⌈
n
2
⌉
x^{\lceil\frac{n}{2}\rceil}
x⌈2n⌉的倍数,所以在模
x
⌈
n
2
⌉
x^{\lceil\frac{n}{2}\rceil}
x⌈2n⌉意义下也与
A
(
x
)
A(x)
A(x)相同,所以在模
x
⌈
n
2
⌉
x^{\lceil\frac{n}{2}\rceil}
x⌈2n⌉意义下
ln
f
(
x
)
\ln f(x)
lnf(x)和
ln
f
0
(
x
)
\ln f_0(x)
lnf0(x)相等,进一步可以推出在模
x
⌈
n
2
⌉
x^{\lceil\frac{n}{2}\rceil}
x⌈2n⌉意义下
f
(
x
)
f(x)
f(x)与
f
0
(
x
)
f_0(x)
f0(x)相等,都是
0
0
0。于是就有
(
f
(
x
)
−
f
0
(
x
)
)
2
=
0
(
m
o
d
x
n
)
(f(x)-f_0(x))^2=0(mod\ x^n)
(f(x)−f0(x))2=0(mod xn),原因是原来前
⌈
n
2
⌉
\lceil\frac{n}{2}\rceil
⌈2n⌉次项在模
x
⌈
n
2
⌉
x^{\lceil\frac{n}{2}\rceil}
x⌈2n⌉意义下是
0
0
0,所以平方后前
n
n
n次项的系数都是
0
0
0,由此可得
(
f
(
x
)
−
f
0
(
x
)
)
m
(f(x)-f_0(x))^m
(f(x)−f0(x))m中所有次数
m
m
m大于等于2的项在模
x
n
x^n
xn意义下都是
0
0
0了,于是我们只需要保留前两项即可,也就是
g
(
f
(
x
)
)
≡
g
(
f
0
(
x
)
)
+
g
′
(
f
0
(
x
)
)
(
f
(
x
)
−
f
0
(
x
)
)
(
m
o
d
x
n
)
g(f(x))\equiv g(f_0(x))+g'(f_0(x))(f(x)-f_0(x))(mod\ x^n)
g(f(x))≡g(f0(x))+g′(f0(x))(f(x)−f0(x))(mod xn)。化简一下就是
f
(
x
)
=
f
0
(
x
)
−
g
(
f
0
(
x
)
)
g
′
(
f
0
(
x
)
)
(
m
o
d
x
n
)
f(x)=f_0(x)-\frac{g(f_0(x))}{g'(f_0(x))}(mod\ x^n)
f(x)=f0(x)−g′(f0(x))g(f0(x))(mod xn) 再利用一下复合函数的求导公式可得:
f
(
x
)
=
f
0
(
x
)
(
1
−
ln
f
0
(
x
)
+
A
(
x
)
)
(
m
o
d
x
n
)
f(x)=f_0(x)(1−\ln f_0(x)+A(x))(mod\ x^n)
f(x)=f0(x)(1−lnf0(x)+A(x))(mod xn)
这个东西要用多项式牛顿迭代。具体实现的话就是用一种倍增的方法,复杂度证明和多项式求逆差不多。式子中的 ln \ln ln用多项式对数函数就好,推导就到这里了。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,l,rev[800010];
long long a[800010],b[800010],xx[800010],yy[800010],zz[800010],c[800010],d[800010];
const long long mod=998244353,g=3,gi=332748118;
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)
{
l=0;
m=len;
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 x=a[j+k],y=w*a[i+j+k]%mod;
a[j+k]=(x+y)%mod;
a[i+j+k]=(x-y+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)
{
xx[i]=a[i];
yy[i]=b[i];
}
ntt(xx,1,len<<1);
ntt(yy,1,len<<1);
for(int i=0;i<(len<<1);++i)
xx[i]=xx[i]*yy[i]%mod*yy[i]%mod;
ntt(xx,-1,len<<1);
for(int i=0;i<len;++i)
b[i]=(b[i]*2-xx[i]+mod)%mod;
for(int i=0;i<(len<<1);++i)
{
xx[i]=0;
yy[i]=0;
}
}
inline void ln(long long *a,long long *b,int len)
{
for(int i=1;i<len;++i)
d[i-1]=a[i]*i%mod;
inv(a,zz,len);
ntt(d,1,len<<1);
ntt(zz,1,len<<1);
for(int i=0;i<(len<<1);++i)
d[i]=d[i]*zz[i];
ntt(d,-1,len<<1);
for(int i=1;i<len;++i)
b[i]=d[i-1]*ksm(i,mod-2)%mod;
b[0]=0;
for(int i=0;i<(len<<1);++i)
{
d[i]=0;
zz[i]=0;
}
}
/*inline void exp(long long *a,long long *b,int len)
{
if(len==1)
{
b[0]=1;
return;
}
exp(a,b,len>>1);
ln(b,yy,len);
for(int i=0;i<n;++i)
xx[i]=a[i];
ntt(xx,1,len<<1);
ntt(yy,1,len<<1);
ntt(b,1,len<<1);
for(int i=0;i<(len<<1);++i)
b[i]=b[i]*(1-yy[i]+xx[i]+mod)%mod;
ntt(b,-1,len<<1);
for(int i=n;i<(len<<1);++i)
b[i]=0;
for(int i=0;i<(len<<1);++i)
{
xx[i]=0;
yy[i]=0;
}
}*/
inline void exp(long long *a,long long *b,int len)
{
if(len==1)
{
b[0]=1;
return;
}
exp(a,b,len>>1);
ln(b,yy,len);
for(int i=0;i<len;++i)
xx[i]=a[i];
xx[0]++;
for(int i=0;i<len;++i)
yy[i]=(xx[i]-yy[i]+mod)%mod;
ntt(yy,1,len<<1);
ntt(b,1,len<<1);
for(int i=0;i<(len<<1);++i)
b[i]=b[i]*yy[i]%mod;
ntt(b,-1,len<<1);
for(int i=n;i<(len<<1);++i)
b[i]=0;
for(int i=0;i<(len<<1);++i)
{
xx[i]=0;
yy[i]=0;
}
}
int main()
{
scanf("%d",&n);
for(int i=0;i<=n-1;++i)
a[i]=read();
int ji;
for(ji=1;ji<=n;ji<<=1);
exp(a,c,ji);
for(int i=0;i<n;++i)
printf("%lld ",c[i]);
printf("\n");
return 0;
}