多项式对数函数(多项式 ln)
前置知识
\(\ln\) 求导
求 \(\ln'(t)\)。
结论
\[\ln'(t)=\frac{1}{t}
\]
证明
设:
\[\frac{1}{\varepsilon}\ln(1+\frac{\varepsilon}{t})=k
\]
\[\frac{1}{k\varepsilon}\ln(1+\frac{\varepsilon}{t})=1
\]
\[(1+\frac{\varepsilon}{t})^{\frac{1}{k\varepsilon}}=e=\lim_{x\to\infty}\limits (1+\frac{1}{x})^x
\]
那么就得到了:
\[\begin{cases} \frac{\varepsilon}{t}=\frac{1}{x}\\ \frac{1}{k\varepsilon}=x \end{cases}
\]
相乘得到:
\[\frac{1}{kt}=1
\]
那么:
\[k=\frac{1}{t}
\]
\[\ln'(t)=\frac{1}{t}
\]
至此,证毕。
多项式求导
求 \(f'(x)\)。
结论
\([x^t]f(x)\cdot x^t\to t\cdot [x^t]f(x)\cdot x^{t-1}\)
写得和蔼一点就是:\(a_i\cdot x^{i}\to a_i\cdot i\cdot x^{i-1}\)
积分同理,即回带。
证明
稍微咕一下,就一下。
复合函数求导法则
结论
\(h(x)=f[g(x)],h'(x)=f'[g(x)]\cdot g'(x)\)
证明
稍微咕一下,就
多项式求 \(\ln\)
求 \(\ln(f(x))=g(x)\)。
\[g'(x)=\ln'(f(x))\cdot f'(x)=\frac{1}{f(x)}\cdot f'(x)
\]
正题
由前面我们已经发现了 \(\ln\) 函数的优美性质,其导数为 \(\frac{1}{x}\)。
结合复合函数求导公式,我们就可以干一些好玩的事情。
对于:
\[\ln A(x)\equiv B(x)\pmod p
\]
我们就可以通过复合函数求导得到:
\[\ln' A(x) \cdot A'(x)\equiv B'(x)
\]
\[\frac{1}{A(x)}\cdot A'(x)\equiv B'(x)
\]
对于给定的 \(A\),第一项,我们可以由求逆得到,第二项,由多项式求导得到。
于是我们就可以将两者卷起来求得 \(B\) 的导数,然后将其转回去得到系数。
这里有个有趣的小细节,就是实际上,转回去之后,我们会不知道常数项,这应该怎么办呢?实际上常数项就是 \(0\),至于为什么,之后在 exp 部分会详细证明。
代码
#include <stdio.h>
#define LL long long
using namespace std;
const int N=3e5+3;
const int M=998244353;
const int K=3;
inline int rin()
{
int s=0;
bool bj=false;
char c=getchar();
for(;(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')bj=true,c=getchar();
for(;c>='0'&&c<='9';c=getchar())s=(s<<1)+(s<<3)+(c^'0');
if(bj)s=-s;
return s;
}
inline int prpr(int x,int y){return 1LL*x*y%M;}
inline int ksm(int x,int y){int ans=1;for(;y;y>>=1){if(y&1)ans=prpr(ans,x);x=prpr(x,x);}return ans;}
inline void jh(int &x,int &y){if(x!=y)x^=y^=x^=y;return;}
const int Kr=ksm(K,M-2);
int num[N];
int lens;
inline void init(int L)
{
int lg=0;
for(lens=1;lens<L;lens<<=1)lg++;
for(int i=0;i<lens;i++)num[i]=((num[i>>1]>>1)|((i&1)<<lg-1));
return;
}
inline void NTT(int *a,int tag)
{
for(int i=0;i<lens;i++)if(i>num[i])jh(a[i],a[num[i]]);
for(int i=1;i<lens;i<<=1)
{
int Gyq=ksm(tag?K:Kr,(M-1)/(i<<1));
for(int j=0;j<lens;j+=(i<<1))
{
int Zjj=1;
for(int k=0;k<i;k++,Zjj=prpr(Zjj,Gyq))
{
int x=a[j+k],y=prpr(a[j+k+i],Zjj);
a[j+k]=(x+y)%M;
a[j+k+i]=(x-y+M)%M;
}
}
}
if(!tag)
{
int Gyq=ksm(lens,M-2);
for(int i=0;i<lens;i++)a[i]=prpr(a[i],Gyq);
}
return;
}
int Alpha[N];
inline void inv(int *a,int *b,int L)
{
if(L==1){b[0]=ksm(a[0],M-2);return;}
inv(a,b,(L+1)>>1);
init((L<<1)-1);
for(int i=0;i<L;i++)Alpha[i]=a[i];
for(int i=L;i<lens;i++)Alpha[i]=0;
NTT(Alpha,1);
NTT(b,1);
for(int i=0;i<lens;i++)b[i]=prpr(b[i],2-prpr(Alpha[i],b[i]));
NTT(b,0);
for(int i=L;i<lens;i++)b[i]=0;
return;
}
inline void der(int *a,int L){for(int i=1;i<L;i++)a[i-1]=prpr(a[i],i);for(int i=L;i<lens;i++)a[i]=0;return;}
int n;
int a[N];
int b[N];
int sl[N];
int sr[N];
int main()
{
n=rin()-1;
for(int i=0;i<=n;i++)a[i]=rin();
inv(a,b,n+1);
init(n+n+1);
der(a,n+1);
NTT(a,1);
NTT(b,1);
for(int i=0;i<lens;i++)b[i]=prpr(b[i],a[i]);
NTT(b,0);
sl[0]=sr[0]=1;
for(int i=1;i<=n;i++)sl[i]=prpr(sl[i-1],i);
sr[n]=ksm(sl[n],M-2);
for(int i=n-1;i>=1;i--)sr[i]=prpr(sr[i+1],i+1);
for(int i=n;i>=1;i--)b[i]=prpr(prpr(b[i-1],sr[i]),sl[i-1]);
b[0]=0;
for(int i=0;i<=n;i++)printf("%d ",(b[i]%M+M)%M);printf("\n");
return 0;
}
$$\texttt{Dirty Deeds Done Dirt Cheap}$$