多项式对数函数(多项式求ln)小结

多项式对数函数

顾名思义,给出一个多项式 A ( x ) A(x) A(x),求出一个多项式 G ( x ) G(x) G(x),满足 G ( x ) = ln ⁡ A ( x ) ( m o d x n ) G(x)=\ln A(x)\pmod {x^n} G(x)=lnA(x)(modxn)

F ( x ) = ln ⁡ ( x ) F(x)=\ln (x) F(x)=ln(x),那么有 G ( x ) = F ( A ( x ) ) G(x)=F(A(x)) G(x)=F(A(x)),对等式两边同时求导,得到
G ′ ( x ) = F ′ ( A ( x ) ) A ′ ( x ) G'(x)=F'(A(x))A'(x) G(x)=F(A(x))A(x)

而我们又知道,对数函数的导数就是倒数,即 F ′ ( x ) = 1 x F'(x)=\dfrac 1 x F(x)=x1,于是有
F ′ ( A ( x ) ) A ′ ( x ) = A ′ ( x ) A ( x ) F'(A(x))A'(x)=\frac {A'(x)} {A(x)} F(A(x))A(x)=A(x)A(x)

所以先多项式求逆算出 1 A ( x ) \frac 1 {A(x)} A(x)1,然后对 A ( x ) A(x) A(x) 求导得到 A ′ ( x ) A'(x) A(x),乘起来得到 G ′ ( x ) G'(x) G(x),最后积分一下得到 G ( x ) G(x) G(x)

以及一开始的 n n n 需要像 n t t ntt ntt 那样求出第一个大于 n n n 的二次幂,然后再丢进去求 ln ⁡ \ln ln,不然会因为不明原因WA掉qwq……

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 800010
#define mod 998244353

int n,F[maxn],G[maxn];
int ksm(int x,int y)
{
	int re=1;
	while(y)
	{
		if(y&1)re=1ll*re*x%mod;
		x=1ll*x*x%mod;y>>=1;
	}
	return re;
}
#define inv(x) ksm(x,mod-2)
void Dao(int *f,int *g,int len){for(int i=0;i<len-1;i++)g[i]=1ll*f[i+1]*(i+1)%mod;g[len-1]=0;}
void Jifen(int *f,int *g,int len){for(int i=len-1;i>0;i--)g[i]=1ll*f[i-1]*inv(i)%mod;g[0]=0;}
const int g=3,inv_g=inv(g);
int limit,l,r[maxn];
void get(int len)
{
	limit=1,l=0;while(limit<=len)limit<<=1,l++;
	for(int i=1;i<limit;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
}
void ntt(int *f,int type)
{
	for(int i=1;i<limit;i++)if(i<r[i])swap(f[i],f[r[i]]);
	for(int mid=1;mid<limit;mid<<=1)
	{
		int wn=ksm((type==1?g:inv_g),(mod-1)/2/mid);
		for(int block=mid<<1,j=0;j<limit;j+=block)
		for(int i=j,w=1;i<j+mid;i++,w=1ll*w*wn%mod)
		{
			int x=f[i],y=1ll*f[i+mid]*w%mod;
			f[i]=(x+y)%mod;f[i+mid]=(x-y+mod)%mod;
		}
	}
}
int A[maxn],B[maxn];
void getinv(int len,int *f,int *g)
{
	if(len==1){g[0]=inv(f[0]);return;}
	getinv((len+1)>>1,f,g); get(len*2);
	for(int i=0;i<len;i++)A[i]=f[i],B[i]=g[i];
	for(int i=len;i<limit;i++)A[i]=B[i]=0;
	ntt(A,1);ntt(B,1);for(int i=0;i<limit;i++)A[i]=1ll*B[i]*(2ll-1ll*A[i]*B[i]%mod+mod)%mod;
	ntt(A,-1);for(int i=0,inv_limit=inv(limit);i<limit;i++)g[i]=1ll*A[i]*inv_limit%mod;
}
int a[maxn],b[maxn];
void getln(int *f,int *g,int len)
{
	getinv(len,f,b);Dao(f,a,len);get(len*2);
	ntt(a,1);ntt(b,1);for(int i=0;i<limit;i++)a[i]=1ll*a[i]*b[i]%mod;
	ntt(a,-1);for(int i=0,inv_limit=inv(limit);i<limit;i++)a[i]=1ll*a[i]*inv_limit%mod;
	Jifen(a,g,len);
}

int main()
{
	scanf("%d",&n);int m;
	for(int i=0;i<n;i++)scanf("%d",&F[i]);
	for(m=1;m<=n;m<<=1);getln(F,G,m);
	for(int i=0;i<n;i++)printf("%d ",G[i]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值