背景:
多项式全家桶
eating...
\text{eating...}
eating...
简单了解了导数和积分(选修
2
−
2
2-2
2−2),应该足够应对这道题了。
题目传送门:
https://www.luogu.org/problemnew/show/P4725
题意:
给定一个多项式
F
(
x
)
F(x)
F(x),求
G
(
x
)
≡
ln
F
(
x
)
(
m
o
d
  
x
n
)
G(x)≡\ln F(x)(\mod x^n)
G(x)≡lnF(x)(modxn)。
思路:
另一个函数
f
(
x
)
=
ln
(
x
)
f(x)=\ln(x)
f(x)=ln(x),则有:
G
(
x
)
≡
f
(
F
(
x
)
)
(
m
o
d
  
x
n
)
G(x)≡f(F(x))(\mod x^n)
G(x)≡f(F(x))(modxn)
容易发现
f
(
F
(
x
)
)
f(F(x))
f(F(x))是一个复合函数,两边同时取导,因此有:
G
′
(
x
)
≡
f
′
(
F
(
x
)
)
F
′
(
x
)
(
m
o
d
  
x
n
)
G'(x)≡f'(F(x))F'(x)(\mod x^n)
G′(x)≡f′(F(x))F′(x)(modxn)
因为
f
(
x
)
=
ln
(
x
)
,
ln
′
(
x
)
=
1
x
f(x)=\ln(x),\ln'(x)=\frac{1}{x}
f(x)=ln(x),ln′(x)=x1,所以
f
′
(
x
)
=
1
x
,
f
′
(
F
(
x
)
)
=
1
F
(
x
)
f'(x)=\frac{1}{x},f'(F(x))=\frac{1}{F(x)}
f′(x)=x1,f′(F(x))=F(x)1。
G
′
(
x
)
≡
F
′
(
x
)
F
(
x
)
(
m
o
d
  
x
n
)
G'(x)≡\frac{F'(x)}{F(x)}(\mod x^n)
G′(x)≡F(x)F′(x)(modxn)
对于输入的 F ( x ) F(x) F(x),我们求一次导,得 F ′ ( x ) F'(x) F′(x),求一次逆得到 1 F ( x ) \frac{1}{F(x)} F(x)1,合并得到 G ′ ( x ) G'(x) G′(x),最后对 G ′ ( x ) G'(x) G′(x)求一次不定积分即可。
求导可用公式:若
f
(
x
)
=
x
a
f(x)=x^a
f(x)=xa,则
f
′
(
x
)
=
a
x
a
−
1
f'(x)=ax^{a-1}
f′(x)=axa−1;
百度不定积分,发现其有这样一条公式
∫
x
a
d
x
=
x
a
+
1
a
+
1
\int x^adx=\frac{x^{a+1}}{a+1}
∫xadx=a+1xa+1,便可不定积分解决了。
为什么选择指数的求导和不定积分啊,多项式不就是由
a
0
x
0
+
a
1
x
1
+
a
2
x
2
+
.
.
.
+
a
k
x
k
a_0x^0+a_1x^1+a_2x^2+...+a_kx^k
a0x0+a1x1+a2x2+...+akxk组成的吗?
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
const LL mod=998244353,G=3,inv_G=332748118;
using namespace std;
LL a[300010],b[300010],f[300010],g1[300010],g2[300010];
int limit,n,l,r[300010];
LL dg(LL x,LL k)
{
if(!k) return 1;
LL op=dg(x,k>>1);
if(k&1) return op*op%mod*x%mod; else return op*op%mod;
}
LL inv(LL x)
{
return dg(x,mod-2);
}
void dao(LL *f,LL *g,int n)
{
for(int i=1;i<n;i++)
g[i-1]=i*f[i]%mod;
g[n-1]=0;
}
void jifen(LL *f,LL *g,int n)
{
for(int i=1;i<n;i++)
g[i]=f[i-1]*inv(i)%mod;
g[0]=0;
}
void init(int n)
{
limit=1,l=0;
while(limit<(n<<1))
limit<<=1,l++;
for(int i=1;i<limit;i++)
r[i]=((r[i>>1]>>1)|((i&1)<<(l-1)));
}
void NTT(LL *now,int limit,int op)
{
for(int i=0;i<limit;i++)
if(i<r[i]) swap(now[i],now[r[i]]);
for(int mid=1;mid<limit;mid<<=1)
{
LL wn=dg(op==1?G:inv_G,(mod-1)/(mid<<1));
for(int j=0;j<limit;j+=(mid<<1))
{
LL w=1;
for(int k=0;k<mid;k++,w=(w*wn)%mod)
{
LL x=now[j+k],y=w*now[j+k+mid]%mod;
now[j+k]=(x+y)%mod;
now[j+k+mid]=(x-y+mod)%mod;
}
}
}
}
void dft(LL *f,int n,int limit)
{
NTT(f,limit,-1);
LL INV=inv(limit);
for(int i=0;i<n;i++)
f[i]=f[i]*INV%mod;
}
void poly_inv(LL *f,LL *g,int n)
{
if(n==1)
{
g[0]=inv(f[0]);
return;
}
poly_inv(f,g,(n+1)>>1);
init(n);
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=0;i<n;i++)
a[i]=f[i],b[i]=g[i];
NTT(a,limit,1),NTT(b,limit,1);
for(int i=0;i<limit;i++)
b[i]=b[i]*((2ll-a[i]*b[i]%mod+mod)%mod)%mod;
dft(b,n,limit);
for(int i=0;i<n;i++)
g[i]=b[i];
}
void poly_ln(LL *f)
{
dao(f,g1,n);
poly_inv(f,g2,n);
init(n);
NTT(g1,limit,1),NTT(g2,limit,1);
for(int i=0;i<limit;i++)
g1[i]=g1[i]*g2[i]%mod;
dft(g1,n,limit);
jifen(g1,g2,n);
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lld",&f[i]);
poly_ln(f);
for(int i=0;i<n;i++)
printf("%lld ",g2[i]);
}