luogu P4725 【模板】多项式对数函数(多项式 ln)

18 篇文章 0 订阅

背景:

多项式全家桶 eating... \text{eating...} eating...
简单了解了导数和积分(选修 2 − 2 2-2 22),应该足够应对这道题了。

题目传送门:

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)=axa1
百度不定积分,发现其有这样一条公式 ∫ 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]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值