多项式求逆 学习笔记 洛谷4238

题目链接

给定一个多项式 F ( x ) F(x) F(x),请求出一个多项式 G ( x ) G(x) G(x), 满足 F ( x ) ∗ G ( x ) ≡ 1 ( m o d   x n ) F(x) * G(x) \equiv 1 ( mod\ x^n ) F(x)G(x)1(mod xn)
。系数对 998244353 998244353 998244353取模。 n &lt; = 1 e 5 n&lt;=1e5 n<=1e5

这个东西要用到一种叫多项式求逆的算法。我们设 f ( x ) f(x) f(x)在模 x ⌈ n 2 ⌉ x^{\lceil\frac{n}{2}\rceil} x2n时的逆元是 g ( x ) g(x) g(x),即 f ( x ) ∗ g ( x ) = 1 ( m o d   x ⌈ n 2 ⌉ ) f(x)*g(x)=1(mod\ x^{\lceil\frac{n}{2}\rceil}) f(x)g(x)=1(mod x2n),设我们要求的逆元是 f ′ ( x ) f&#x27;(x) f(x)。那么根据取模的性质,有 f ( x ) ∗ f ′ ( x ) = 1 ( m o d   x ⌈ n 2 ⌉ ) f(x)*f&#x27;(x)=1(mod\ x^{\lceil\frac{n}{2}\rceil}) f(x)f(x)=1(mod x2n)。由此可得: f ( x ) ∗ ( f ′ ( x ) − g ( x ) ) = 0 ( m o d   x ⌈ n 2 ⌉ ) f(x)*(f&#x27;(x)-g(x))=0(mod\ x^{\lceil\frac{n}{2}\rceil}) f(x)(f(x)g(x))=0(mod x2n) 由于 f ( x ) f(x) f(x)不是 0 0 0,所以除掉 f ( x ) f(x) f(x),得到: ( f ′ ( x ) − g ( x ) ) = 0 ( m o d   x ⌈ n 2 ⌉ ) (f&#x27;(x)-g(x))=0(mod\ x^{\lceil\frac{n}{2}\rceil}) (f(x)g(x))=0(mod x2n)
平方可得: ( f ′ ( x ) − g ( x ) ) 2 = 0 ( m o d   x n ) (f&#x27;(x)-g(x))^2=0(mod\ x^n) (f(x)g(x))2=0(mod xn) 展开左边 f ′ ( x ) 2 − 2 ∗ f ′ ( x ) ∗ g ( x ) + g ( x ) 2 = 0 ( m o d   x n ) f&#x27;(x)^2-2*f&#x27;(x)*g(x)+g(x)^2=0(mod\ x^n) f(x)22f(x)g(x)+g(x)2=0(mod xn) 由于 f ′ ( x ) f&#x27;(x) f(x) f ( x ) f(x) f(x)的逆元,所以同乘一个 f ( x ) f(x) f(x)可以化简: f ′ ( x ) 2 ∗ f ( x ) − 2 ∗ f ′ ( x ) ∗ f ( x ) ∗ g ( x ) + g ( x ) 2 ∗ f ( x ) f&#x27;(x)^2*f(x)-2*f&#x27;(x)*f(x)*g(x)+g(x)^2*f(x) f(x)2f(x)2f(x)f(x)g(x)+g(x)2f(x)
f ′ ( x ) − 2 g ( x ) + f ( x ) ∗ g ( x ) 2 = 0 ( m o d   x n ) f&#x27;(x)-2g(x)+f(x)*g(x)^2=0(mod\ x^n) f(x)2g(x)+f(x)g(x)2=0(mod xn) 移项可得: f ′ ( x ) = 2 g ( x ) − f ( x ) ∗ g ( x ) ∗ g ( x ) f&#x27;(x)=2g(x)-f(x)*g(x)*g(x) f(x)=2g(x)f(x)g(x)g(x) 这样我们就可以由一个指数是当前 n n n一半时的逆元推出当前模数指数是 n n n时的逆元了,相当于一个倍增的过程,而其中需要多项式乘法,这个要用NTT。

分析一波复杂度: T ( n ) = T ( n 2 ) + O ( n l o g n ) T(n)=T(\frac{n}{2})+O(nlogn) T(n)=T(2n)+O(nlogn),我们设 O ( n l o g n ) O(nlogn) O(nlogn) x x x,我们会发现这个过程中运算量是 x + x 2 + x 4 + . . . x+\frac{x}{2}+\frac{x}{4}+... x+2x+4x+...,这个东西是不超过 2 x 2x 2x的,也就是不超过 O ( 2 n l o g n ) O(2nlogn) O(2nlogn)的,所以总复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)

代码:

#include <bits/stdc++.h>
using namespace std;

int n,m,l,rev[500010],ji;
const double pi=acos(-1);
const long long g=3,gi=332748118,mod=998244353;
long long a[500010],b[500010],x[500010],y[500010];
inline int read()
{
	int x=0;
	char s=getchar();
	while(s>'9'||s<'0')
	s=getchar();
	while(s>='0'&&s<='9')
	{
		x=x*10+s-'0';
		s=getchar();
	}
	return x;
}
inline long long ksm(long long x,long long y)
{
	long long res=1;
	while(y)
	{
		if(y&1)
		res=res*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return res;
}
inline void ntt(long long *a,int dft,int len)
{
	m=len;
	l=0;
	for(len=1;len<m;len<<=1)
	++l;
	for(int i=0;i<len;++i)
	rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
	for(int i=0;i<len;++i)
	{
		if(i<rev[i])
		swap(a[i],a[rev[i]]);
	}
	for(int i=1;i<len;i<<=1)
	{
		long long wn=ksm((dft==1?g:gi),(mod-1)/(i<<1));
		for(int j=0,p=i<<1;j<len;j+=p)
		{
			long long w=1;
			for(int k=0;k<i;++k)
			{
				long long xx=a[j+k],yy=w*a[i+j+k]%mod;
				a[j+k]=(xx+yy)%mod;
				a[i+j+k]=(xx-yy+mod)%mod;
				w=w*wn%mod;
			}
		}
	}
	if(dft==-1)
	{
		long long ni=ksm(m,mod-2);
		for(int i=0;i<len;++i)
		a[i]=a[i]*ni%mod;
	}
}
inline void inv(long long *a,long long *b,int len)
{
	if(len==1)
	{
		b[0]=ksm(a[0],mod-2);
		return;
	}
	inv(a,b,len>>1);
	for(int i=0;i<len;++i)
	{
		x[i]=a[i];
		y[i]=b[i];
	}		
	ntt(x,1,len<<1);
	ntt(y,1,len<<1);	
	for(int i=0;i<(len<<1);++i)
	x[i]=x[i]*y[i]%mod*y[i]%mod;	
	ntt(x,-1,len<<1);	
	for(int i=0;i<len;++i)
	b[i]=(b[i]*2%mod-x[i]+mod)%mod;
}
int main()
{
	n=read();
	ji=n;
	for(int i=0;i<=n-1;++i)
	a[i]=read()%mod;
	for(n=1;n<ji;n<<=1);	
	inv(a,b,n);
	for(int i=0;i<ji;++i)
	printf("%lld ",b[i]);
	printf("\n");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值