题解 P10249【【模板】多项式复合函数】

Link

力求把最新技术翻译地人人都能看懂。

推荐先学习:多项式复合逆转置原理

题意

给出两个 n 次多项式 F(x),G(x),求出 H(x)F(G(x))(modxn+1)

n2×105

思路

我们有:

hi=j=0nfj[xi]Gj(x)

那么这是由 fh 的一个线性变换,不妨考虑转置原理,该问题的转置为:

fj=i=0nhi[xi]Gj(x)

不难发现 F(x)=[xn]HR(x)1yG(x),其中 HR(x) 表示把 H(x) 系数翻转得到的多项式。如果 H(x) 是输入,F(x) 是输出,那么我们可以直接使用 Bostan-Mori 算法得到答案,那么根据转置原理,我们写出该算法的转置即可。可以配合代码理解。

关于 Bostan-Mori 算法的过程与复杂度证明,可参见多项式复合逆

时间复杂度 O(nlog2n)

核心代码:

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;
namespace MulTT{
	inline Poly MulT(const Poly &a,const Poly &b){
		Poly F=a,G=b;
		int n=a.size(),m=b.size();
		reverse(G.begin(),G.end());
		init(n);
		F.resize(lim),G.resize(lim);
		NTT(F,1),NTT(G,1);
		for(int i=0;i<lim;i++)
			G[i]=1ll*F[i]*G[i]%mod;
		NTT(G,-1);
		for(int i=m-1;i<n;i++)
			F[i-m+1]=G[i];
		F.resize(max(0,n-m+1));
		return F;
	}
	inline PolyY MulT(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.resize(m*p);
		for(int i=0;i<n;i++)
			for(int j=0;j<p;j++)
				P[i*p+j]=a[i][j];
		for(int i=0;i<m;i++)
			for(int j=0;j<q;j++)
				Q[i*p+j]=b[m-1-i][q-1-j];
		init(n*p);
		P.resize(lim),Q.resize(lim);
		NTT(P,1),NTT(Q,1);
		for(int i=0;i<lim;i++)
			P[i]=1ll*P[i]*Q[i]%mod;
		NTT(P,-1);
		PolyY F(n-m+1,Poly(p-q+1,0));
		for(int i=m-1;i<n;i++)
			for(int j=q-1;j<p;j++)
				F[i-m+1][j-q+1]=P[i*p+j]; 
		return F;
	}
}
using namespace MulTT;
inline PolyY BostanMoriT(int n,Poly P,PolyY G){
	if(!n){
		int p=G[0].size();
		P.resize(p*2-1);
		return {MulT(P,Inv(G[0]))};
	}
	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]);
	G=G*H;
	PolyY A,B;
	for(int i=0;i<G.size();i+=2) B.push_back(G[i]);
	PolyY F=BostanMoriT(n/2,P,B);
	int p=H.size(),q=F[0].size();
	A.resize(p*2);
	for(int i=0,j=0;i<p*2;i++){
		if((i&1)==(n&1)&&j<F.size()) A[i]=F[j++];
		else A[i]=Poly(q,0);
	}
	F=MulT(A,H);
	return F;
}
inline Poly Comp(Poly F,Poly G){
	int n=F.size();
	G.resize(n);
	PolyY Q;
	for(int i=0;i<n;i++)
		Q.push_back({!i,dec(0,G[i])});
	PolyY P=BostanMoriT(n-1,F,Q);
	Poly H(n,0); 
	for(int i=0;i<n;i++)
		H[n-1-i]=P[i][0];
	return H;
}
posted @   ffffyc  阅读(56)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示