多项式基础运算

前置知识:NTT

多项式乘法逆

加减乘都完成了,我们还差一个除:

数字在取模运算中的乘法,我们通常用求逆元来完成,所以我们先来看看多项式的乘法逆:

考虑递归求解,我们要求的是\(F(x)\)满足

\[G(x)F(x)\equiv 1\pmod {x^n} \]

假设我们已经求出了\(F_0(x)\)满足

\[G(x)F_0(x)\equiv 1\pmod {x^\frac n2} \]

又因为

\[G(x)F(x)\equiv 1\pmod {x^\frac n2} \]

\[F(x)-F_0(x)\equiv 0\pmod {x^\frac n2} \]

两边平方得:

\[F^2(x)+F_0^2(x)-2F(x)F_0(x)\equiv 0\pmod {x^n} \]

左右两边同成\(G(x)\)得:

\[G(x)F^2(x)+G(x)F_0^2(x)-2G(x)F(x)F_0(x)\equiv 0\pmod {x^n} \]

因为

\[G(x)F(x)\equiv 1\pmod {x^n} \]

所以

\[F(x)+G(x)F_0^2(x)-2F_0(x)\equiv0\pmod{x^n} \]

\[F(x) \equiv2F_0(x)-G(x)F_0^2(x)\pmod{x^n} \]

然后就可以递归了,边界就是\(F(x)\)只有一项时,\(G(x)\)就是这一项的逆元。

这里只给出了,求逆部分的代码,容器及\(NTT\)请参见我的上一篇博客

inline poly getinv(int n,poly f){
	if(n==1){poly g;g[0]=ksm(f[0],mod-2);return g;}
	int t=(n+1)>>1;
	poly g=getinv(t,f);poly p=g;
	
	int lim=1,len=0;
	while(lim<(n<<1)) lim<<=1,len++;
	for(int i=0;i<lim;++i) r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
	if(f.size()>n) f.mem(n,min(lim,f.size())-1,0);
	if(p.size()>n) p.mem(n,min(lim,g.size())-1,0);
		
	NTT(lim,f,1);NTT(lim,p,1);
	f=f*p*p;
	NTT(lim,f,-1);
	int iv=ksm(lim,mod-2);
	poly h;
	for(int i=0;i<n;++i) h[i]=dec(2ll*g[i]%mod,1ll*f[i]*iv%mod);
	return h;
} 

多项式对数函数(多项式ln)

考虑求的是:

\[B(x)=F(A(x)),F(x)=\ln\ x \]

对两边求导:

\[B'(x)=F'(A(x))A'(x)=\frac{A'(x)}{A(x)} \]

这里用到了复合函数的求导法则:

\[(F(G(x)))'=F'(G(x))G'(x) \]

于是对\(A(x)\)求逆并求导,得到\(B'(x)\)后积分回去即可。

根据求导的基本公式\((x^n)'=nx^{n-1}\),于是扫一遍就可以完成多项式的求导与积分(忽略我的函数名):

int inv[N],tp=2;
inline void init(int n){
	if(tp==2) inv[0]=inv[1]=1;
	for(tp;tp<=n;++tp)
		inv[tp]=1ll*(mod-mod/tp)*inv[mod%tp]%mod; 
}
inline void getdao(int n,poly& f){
	for(int i=1;i<n;++i) f[i-1]=1ll*i*f[i]%mod;
	f[n-1]=0;
}
inline void jifen(int n,poly& f){
	init(n);
	for(int i=n-1;i;--i) f[i]=1ll*inv[i]*f[i-1]%mod;
	f[0]=0;
}

\(\ln\)的代码就很简单了:

inline poly getln(int n,poly f){
	poly g=getinv(n,f);getdao(n,f);
	poly h=poly_mul(n,n,f,g);
	jifen(n,h);
	return h;
}

多项式除法

一般的除法,我们直接通过乘其乘法逆来解决,但有些时候,我们不仅要除,还要取模,这该怎么办呢:

我们已知\(n\)次多项式\(F(x)\)\(m\)次多项式\(G(x)\),要求\(n-m\)次多项式\(Q(x)\)和小于\(m\)次的多项式\(R(x)\)满足

\[F(x)=Q(x)G(x)+R(x) \]

我们先引入一种新的操作,对于\(n\)次多项式(注意\(n\)次多项式是最高次数为\(n\)的多项式,但在我的所有代码与题解中,我使用的\(n\)都表示最高次数为\(n-1\)):

\[F_R(x)=x^nF(\frac 1x) \]

展开后可以发现:

\[F_R(x)=f_0x^n+f_1x^{n-1}+f_2x^{n-2}+\dots+f_{n-1}x+f_n \]

没错,这一操作就相当于翻转了\(F(x)\) 的系数,可以\(O(n)\)完成。

利用这个操作,我们去推柿子:

\[F(\frac 1x)=Q(\frac 1x)*G(\frac 1x)+R(\frac 1x)\\ \]

\[x^nF(\frac 1x)=x^{n-m}Q(\frac 1x)*x^mG(\frac 1x)+x^{n-m+1}*x^{m-1}R(\frac 1x) \]

\[F_R(x)=Q_R(x)G_R(x)+x^{n-m+1}R_R(x) \]

因为\(x^{n-m+1}R_R(x)\)的前\(n-m+1\)项系数一定为\(0\),于是

\[F_R(x)\equiv Q_R(x)G_R(x)\pmod{x^{n-m+1}}\\ Q_R(x)\equiv F_R(x)G_R^{-1}(x)\pmod{x^{n-m+1}} \]

求一遍\(G(x)\)的逆,我们就算出\(Q_R(x)\),进而求出\(Q\)了。

至于\(R(x)\),我们直接由

\[R(x)=F(x)-Q(x)*G(x) \]

求出


以上是多项式比较基础的几个运算,更高阶的一些运算(如开根,\(\exp\)等)需要用到更高阶的知识——多项式牛顿迭代

posted @ 2020-12-20 20:27  cjTQX  阅读(234)  评论(0编辑  收藏  举报