題解 P5809【【模板】多項式複合逆】

ffffyc發表於2024-03-21

\(\text{Link}\)

力求把最新技術翻譯地人人都能看懂。

推薦先學習:拉格朗日反演

題意

給出 \(n\) 次多項式 \(F(x)\),求一個 \(n\) 次多項式 \(G(x)\) 滿足 \(F(G(x))\equiv x(\bmod x^{n+1})\)。保證 \([x^0]F(x)=0\)\([x^1]F(x)\ne 0\)

\(n\le 2\times 10^4\)

思路

我們將 \([x^1]F(x)\) 化成 \(1\) 以便後續處理。令 \(F'(x)\) 為原多項式,\(v\)\([x^1]F'(x)\)\(F(x)\)\(\dfrac{F'(x)}{v}\)

那麼我們有:\(F(G(x))=\dfrac{x}{v}\)\(F^k(G(x))=\dfrac{x^k}{v^k}\),根據擴充套件拉格朗日反演,我們有:

\[[x^n]F^k(x)=\frac1{n}\cdot[x^{n-1}]\frac{kx^{k-1}}{v^k}\cdot\frac{x^n}{G^n(x)} \]

\[[x^n]F^k(x)=\frac k {nv^k}\cdot[x^{n-k}]\frac{x^n}{G^n(x)} \]

\[\sum_kx^{n-k}\frac{nv^k}k[x^n]F^k(x)=\left(\frac{G(x)}x\right)^{-n} \]

\[G(x)=x\left(\sum_kx^{n-k}\frac{nv^k}{k}[x^n]F^k(x)\right)^{-1/n} \]

\[G(x)=\frac{x}v\left(\sum_kx^{n-k}\frac{n}{kv^{n-k}}[x^n]F^k(x)\right)^{-1/n} \]

可以發現此處需要開根的多項式常數項為 \(1\),直接用多項式快速冪即可。於是接下來我們的任務就是對 \(\forall k\in[0,n]\) 求出 \([x^n]F^k(x)\)。不難發現,這等價於求多項式 \([x^n]\dfrac{1}{1-yF(x)}\)

首先我們需要了解 Bostan-Mori 演算法,該演算法可在 \(O(k\log k\log n)\) 的複雜度下對 \(O(k)\) 次的多項式 \(F(x),G(x)\) 求出 \([x^n]\dfrac{F(x)}{G(x)}\)。具體地,

\[[x^n]\dfrac{F(x)}{G(x)}=[x^n]\dfrac{F(x)G(-x)}{G(x)G(-x)}=[x^n]\dfrac{F_0(x^2)}{G_0(x^2)}+x\dfrac{F_1(x^2)}{G_0(x^2)} \]

兩邊分別只有偶數次和奇數次有值,根據 \(n\) 的奇偶性取一邊遞迴即可。當 \(n=0\) 時直接返回 \(\dfrac{[x^0]F(x)}{[x^0]G(x)}\) 即可。

二元多項式的情況也是一樣的:

\[[x^n]\dfrac{F(x,y)}{G(x,y)}=[x^n]\dfrac{F(x,y)G(-x,y)}{G(x,y)G(-x,y)}=[x^n]\dfrac{F_0(x^2,y)}{G_0(x^2,y)}+x\dfrac{F_1(x^2,y)}{G_0(x^2,y)} \]

注意到遞迴到第 \(t\) 層時 \(x\) 只需要保留 \(\lfloor\dfrac{n}{2^t}\rfloor\) 次,而 \(y\) 每層次數只會翻倍,只有 \(2^{t+1}\) 次,所以整個二元多項式只有 \(O(n)\) 項。

於是我們在 \(O(n\log^2n)\) 的時間複雜度內解決了多項式複合逆問題。

核心程式碼:

namespace PolyC{
	//...
	#define PolyY vector<Poly>
	inline PolyY operator*(const PolyY &a,const PolyY &b){
		int n=a.size(),m=b.size(),p=a[0].size(),q=b[0].size();
		Poly P,Q;
		P.resize(n*(p+q-1)),Q.resize(m*(p+q-1));
		for(int i=0;i<n;i++)
			for(int j=0;j<p;j++)
				P[i*(p+q-1)+j]=a[i][j];
		for(int i=0;i<m;i++)
			for(int j=0;j<q;j++)
				Q[i*(p+q-1)+j]=b[i][j];
		P=P*Q;
		PolyY F(n+m-1,Poly(p+q-1,0)); 
		for(int i=0;i<n+m-1;i++)
			for(int j=0;j<p+q-1;j++)
				F[i][j]=P[i*(p+q-1)+j]; 
		return F;
	}
}
using namespace PolyC;
inline Poly BostanMori(int n,PolyY F,PolyY G){
	if(!n) return F[0]*Inv(G[0]);
	if(n+1<F.size()) F.resize(n+1);
	if(n+1<G.size()) G.resize(n+1);
	PolyY H=G;
	for(int i=1;i<H.size();i+=2)
		for(int j=0;j<H[i].size();j++)
			H[i][j]=dec(0,H[i][j]);
	F=F*H,G=G*H;
	PolyY A,B;
	for(int i=n&1;i<F.size();i+=2) A.push_back(F[i]);
	for(int i=0;i<G.size();i+=2) B.push_back(G[i]);
	return BostanMori(n/2,A,B);
}
inline Poly CompInv(Poly F){
	int n=F.size();
	int t=F[1],v=qpow(t,mod-2);
	for(int i=0;i<n;i++)
		F[i]=1ll*F[i]*v%mod;
	PolyY P,Q;
	for(int i=0;i<n;i++)
		P.push_back({!i,0}),
		Q.push_back({!i,dec(0,F[i])});
	Poly G=BostanMori(n-1,P,Q),H(n,0); 
	G.resize(n);
	for(int i=0;i<n;i++)
		H[n-1-i]=1ll*G[i]*(n-1)%mod*inv[i]%mod;
	for(int i=0,w=1;i<n;i++,w=1ll*w*v%mod)
		H[i]=1ll*H[i]*w%mod;
	H=Pow(H,mod-inv[n-1]);
	H.insert(H.begin(),0),H.resize(n);
	for(int i=0;i<n;i++)
		H[i]=1ll*H[i]*v%mod;
	return H;
}

相關文章