问题
现在给出一个 n n n 次多项式 A ( x ) A(x) A(x),其中它的常数项为 1 1 1,现在要求解 ln A ( x ) \ln A(x) lnA(x)。
前置知识
求导
现在有一个函数
f
(
x
)
f(x)
f(x),对应着平面直角坐标系上的一条曲线。现在我们要求它在某处(
x
0
x_0
x0)切线的斜率。显然斜率为
lim
x
→
x
0
f
(
x
)
−
f
(
x
0
)
x
−
x
0
\lim_{x\rightarrow x_0}\frac{f(x)-f(x_0)}{x-x_0}
x→x0limx−x0f(x)−f(x0)上式可以记作
f
′
(
x
0
)
=
d
f
d
x
(
x
0
)
f'(x_0)=\frac{df}{dx}(x_0)
f′(x0)=dxdf(x0)其中的
d
X
dX
dX 可以看成
Δ
X
\Delta X
ΔX 趋近于零的结果。
称之为
f
(
x
)
f(x)
f(x) 在
x
0
x_0
x0 处的导数。暂时可以认为,在
f
(
x
)
f(x)
f(x) 的定义域中任何一个
x
0
x_0
x0 处都对应着一个
f
′
(
x
0
)
f'(x_0)
f′(x0),因此所有的
f
′
(
x
0
)
f'(x_0)
f′(x0) 构成一个新的函数
f
′
(
x
)
f'(x)
f′(x),称之为导函数,简称导数。我们称
f
′
(
x
)
f'(x)
f′(x) 为
f
(
x
)
f(x)
f(x) 的导数,
f
(
x
)
f(x)
f(x) 为
f
′
(
x
)
f'(x)
f′(x) 的原函数。
下面给出几条对下面有用的公式
1.
(
x
k
)
′
=
k
x
k
−
1
(x^k)'=kx^{k-1}
(xk)′=kxk−1,其中
k
≠
0
k\not=0
k=0;
2.
(
ln
x
)
′
=
1
x
(\ln x)'=\frac{1}{x}
(lnx)′=x1;
3.
[
a
u
(
x
)
+
b
v
(
x
)
]
′
=
a
u
′
(
x
)
+
b
v
′
(
x
)
[au(x)+bv(x)]'=au'(x)+bv'(x)
[au(x)+bv(x)]′=au′(x)+bv′(x);
4.
u
′
[
v
(
x
)
]
=
d
u
(
v
)
d
v
d
v
(
x
)
d
x
u'[v(x)]=\frac{du(v)}{dv}\frac{dv(x)}{dx}
u′[v(x)]=dvdu(v)dxdv(x)。
事实上,第三条式子与第一条式子结合可以得到多项式函数的求导公式。
假设现在有一个多项式函数
f
(
x
)
=
∑
i
=
0
n
a
i
x
i
f(x)=\sum_{i=0}^na_ix^i
f(x)=i=0∑naixi则
f
′
(
x
)
=
∑
i
=
1
n
i
a
i
x
i
−
1
f'(x)=\sum_{i=1}^{n}ia_ix^{i-1}
f′(x)=i=1∑niaixi−1
不定积分
不定积分就是对于一个导数求其原函数的运算,记
f
(
x
)
=
∫
f
′
(
x
)
d
x
f(x)=\int f'(x)dx
f(x)=∫f′(x)dx但一个导函数所对应的原函数不止一个,都可以写成由某个函数加上一个常数的形式,那个常数有时可以根据边界条件求得。
方法
要求
ln
A
(
x
)
\ln A(x)
lnA(x),我们先把这个式子求导,得到
[
ln
A
(
x
)
]
′
=
d
ln
A
(
x
)
d
A
(
x
)
d
A
(
x
)
d
x
=
1
A
(
x
)
A
′
(
x
)
[\ln A(x)]'=\frac{d\ln A(x)}{dA(x)}\frac{dA(x)}{dx}=\frac{1}{A(x)}A'(x)
[lnA(x)]′=dA(x)dlnA(x)dxdA(x)=A(x)1A′(x)再根据积分的定义,把它积分,就得到了
ln
A
(
x
)
=
∫
[
ln
A
(
x
)
]
′
d
x
=
∫
A
−
1
(
x
)
A
′
(
x
)
d
x
\ln A(x)=\int[\ln A(x)]'dx=\int A^{-1}(x)A'(x)dx
lnA(x)=∫[lnA(x)]′dx=∫A−1(x)A′(x)dx
这个式子表明先要把这个多项式求逆,再乘上原来多项式的导数,最后把它积分就行了。特殊的,由于
A
(
x
)
A(x)
A(x) 常数项为
1
1
1,故取
ln
A
(
x
)
\ln A(x)
lnA(x) 的常数项为
ln
1
=
0
\ln 1=0
ln1=0。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
ll mod=998244353,G[2]={332748118,3};
ll A[450001],invA[450001],f[450001],g[450001],inv;
int len,m,rev[450001];
ll qp(ll x,int y){
if(y==0) return 1ll;
if(y==1) return x;
ll res=qp(x,y>>1);
(res*=res)%=mod;
if(y&1) (res*=x)%=mod;
return res;
}
void NTT(ll *a,int flag,int n){
ll w,w_n,x,y;
for(int i=1;i<n;i+=1){
if(i<rev[i]) swap(a[i],a[rev[i]]);
}
for(int i=1;i<n;i<<=1){
w_n=qp(G[flag],(mod-1)/(i<<1));
for(int j=0;j<n;j+=(i<<1)){
w=1ll;
for(int k=j;k<i+j;k+=1){
x=a[k]; y=(a[k+i]*w)%mod;
a[k]=(x+y)%mod;
a[k+i]=(x-y+mod)%mod;
(w*=w_n)%=mod;
}
}
}
if(!flag){
inv=qp(n,mod-2);
for(int i=0;i<n;i+=1) (a[i]*=inv)%=mod;
}
return;
}
int main(){
int n;
scanf("%d",&len); len-=1;
for(int i=0;i<=len;i+=1) scanf("%lld",&A[i]);
invA[0]=qp(A[0],mod-2);
for(int i=1;i<=len;i<<=1){
memset(g,0,sizeof(g)); m+=1;
for(int j=0;j<i;j+=1) g[j]=invA[j];
for(int j=0;j<(i<<1);j+=1) f[j]=A[j];
for(int j=1;j<(i<<2);j+=1) rev[j]=((rev[j>>1]>>1)|((j&1)<<m));
NTT(g,1,i<<2); NTT(f,1,i<<2);
for(int j=0;j<(i<<2);j+=1) g[j]=(((g[j]*g[j])%mod)*f[j])%mod;
NTT(g,0,i<<2);
for(int j=i;j<(i<<1);j+=1) invA[j]=((invA[j]<<1)%mod-g[j]+mod)%mod;
} //A(x)求逆到invA(x)
for(int i=0;i<len;i+=1){
A[i]=(A[i+1]*(i+1)*1ll)%mod; //A(x)求导到A(x)
}
m=1; while((1<<m)<=(len<<1)) m+=1; n=(1<<m);
NTT(A,1,n); NTT(invA,1,n);
for(int i=0;i<n;i+=1) (A[i]*=invA[i])%=mod; //A'(x)*invA(x)
NTT(A,0,n);
printf("0 ");
for(int i=1;i<=len;i+=1) printf("%lld ",(A[i-1]*qp(i,mod-2))%mod); //积分得到ln A(x)
printf("\n");
return 0;
}
谢谢观看,记得点赞