其他分享
首页 > 其他分享> > 【学习笔记】多项式多项式复合函数

【学习笔记】多项式多项式复合函数

作者:互联网

题意:

给多项式\(F(x)\)和\(G(x)\),求\(n\)次多项式\(H(x)\),满足\(H(x)=F(G(x)) (mod\ x^{n+1})\)。
luogu传送门

思路:

题意具体可以把多项式\(G\)当作自变量,每次次幂后,乘\(F\)的系数。
想要暴力解决问题,试试分块。
令\(L= \left\lceil\sqrt{n}\ \right\rceil\)
\(H(x)=\sum\limits_{i=0}^n([x^i]F(x))*[G(x)]^i (mod\ x^{n+1})\)
\(\ \ \ \ \ \ \ \ \ = \sum\limits_{i=0}^{L-1} [G(x)]^{iL} \sum\limits_{j=0}^{L-1}([x^{iL+j}]F(x))[G(x)]^j\)

可以\(O(\sqrt{n}*nlogn)\)预处理出\(G(x)^i\)以及\(G(x)^{iL}\)
然后\(O(n^2)\)枚举,累加第二个\(\sum\)。
然后第二个\(\sum\)得到的结果和前面多项式乘,用\(O(\sqrt{n}*nlogn)\)
大概总时间复杂度?
\(O(\sqrt{n}nlogn+n^2)\)
而且这个\(n^2\)常数挺低的,时限也很大。

*注意:我因为预处理问题调了很久,预处理时,可能会爆,讨论版有人说\(lim\)最大设为\(n^3-2\)就不会爆,事实上我的就会,我布吉岛别人怎么写的。
我最后还是改回,每算到一次\(G^i\)的值,截断一次(从\(n\)位开始往后赋值为\(0\))。

code:

戳我
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
const int M=100005;
const int L=155;
const int mod=998244353;
int n,m,Blen;
ll A[N],gen[2][N],inv3=332748118,B[L][M],B_[L][M],tb[L][M],tb_[L][M],ans[N],f[N],i_up;
int up,l,rev[N];

ll ksm(ll a,ll b) {ll res=1;for(;b;b>>=1,a=a*a%mod)if(b&1)res=res*a%mod;return res;}

void gt_up(int len) {
	up=1,l=0;
	while(up<=len) {up<<=1,l++;}
	for(int i=1;i<up;i++) {rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));}
}

void NTT(ll *a,int op) {
	for(int i=0;i<up;i++) {
		if(rev[i]>i)swap(a[i],a[rev[i]]);
	}
	for(int mid=1;mid<up;mid<<=1) {
		int len=mid<<1;ll w1=gen[op][len];
 		for(int l=0;l<up;l+=len) {
 			ll W=1;
			for(int i=0;i<mid;i++,W=W*w1%mod) {
				int p=l+i,q=p+mid;
				ll x=a[p],y=W*a[q];
				a[p]=(x+y)%mod;a[q]=(x-y)%mod;
			}
		}
	}
}

void init() {
	scanf("%d%d",&n,&m);n++;m++;
	Blen=ceil(sqrt(n));
	for(int i=0;i<n;i++)scanf("%lld",&A[i]);
	for(int i=0;i<m;i++)scanf("%lld",&B[1][i]),tb[1][i]=B[1][i];
	gt_up(n<<1);
	i_up=ksm(up,mod-2);
//	printf("up=%d\n",up);
	gen[0][up]=ksm(3,(mod-1)/up); gen[1][up]=ksm(inv3,(mod-1)/up);
	for(int i=up;i;i>>=1) {
		gen[0][i>>1]=gen[0][i]*gen[0][i]%mod;
		gen[1][i>>1]=gen[1][i]*gen[1][i]%mod;
	}
	
	tb[0][0]=B[0][0]=B_[0][0]=tb_[0][0]=1;
	NTT(tb[0],0),NTT(tb_[0],0);
	NTT(tb[1],0);
	for(int i=2;i<=Blen;i++) {
		for(int j=0;j<up;j++) B[i][j]=tb[i-1][j]*tb[1][j]%mod;
		NTT(B[i],1);
		for(int j=0;j<n;j++) tb[i][j]=B[i][j]=B[i][j]*i_up%mod;
		for(int j=n;j<up;j++)tb[i][j]=B[i][j]=0;
		NTT(tb[i],0);
	}
//	printf("!%lld!\n",B[1][0]);
	
//	for(int j=0;j<up;j++) tb_[1][j]=tb[Blen][j],B_[1][j]=B[Blen][j];
	for(int j=0;j<n;j++) tb_[1][j]=B_[1][j]=B[Blen][j];
//	for(int j=0;j<up;j++)printf("!%lld %lld\n",tb_[1][j],B_[Blen][j]);
	NTT(tb_[1],0);
	for(int i=2;i<Blen;i++) {
		for(int j=0;j<up;j++) B_[i][j]=tb_[i-1][j]*tb_[1][j]%mod;
		NTT(B_[i],1);
		for(int j=0;j<n;j++) tb_[i][j]=B_[i][j]=B_[i][j]*i_up%mod;
		for(int j=n;j<up;j++) tb_[i][j]=B_[i][j]=0;		//截取 
		NTT(tb_[i],0);
//		printf("i=%d:~~\n",i);
//		for(int j=0;j<n;j++) {printf("%lld ",(B_[i][j]+mod)%mod);}
//		puts("");
	}
}

void solve() {
	for(int i=0;i<Blen;i++) {
//		printf("i=%d~~~~\n",i);
		for(int j=0;j<Blen;j++) {
			ll w=A[i*Blen+j];
			for(int k=0;k<n;k++) {
				f[k]=(f[k]+B[j][k]*w)%mod;
//				printf("(B[%d][%d]=%lld) %lld\n",j,k,(B[j][k]+mod)%mod,(f[k]%mod+mod)%mod); 
			}
		}
//		for(int k=0;k<up;k++)printf("f[%d] = %lld\n",k,(f[k]%mod+mod)%mod); 
		NTT(f,0);
		for(int k=0;k<up;k++) f[k]=f[k]*tb_[i][k]%mod;
		NTT(f,1);
		for(int k=0;k<n;k++) {
			ans[k]=(ans[k]+f[k]*i_up)%mod;
			f[k]=0;
		}
		for(int k=n;k<up;k++)f[k]=0;
	}
	for(int i=0;i<n;i++)printf("%lld ",(ans[i]%mod+mod)%mod);
}

int main() {
//  freopen("data.in","r",stdin);
//	freopen("A.out","w",stdout);
	init();
	solve();
	return 0;
}

ps.说实话,这个东西没什么卵用

标签:int,多项式,ll,复合,笔记,tb,gen,mod
来源: https://www.cnblogs.com/bestime/p/16418327.html