集合划分计数和整数划分计数

集合划分计数

https://www.luogu.com.cn/problem/P5748
https://www.luogu.com.cn/blog/user13052/solution-p5748

\[B(x)=\exp(\exp(x)-1) \]

时间复杂度\(O(n\log n)\)

CO int N=1<<18;
int omg[2][N],rev[N];
int fac[N],inv[N],ifac[N];

void NTT(poly&F,int dir){
	int lim=F.size(),len=log2(lim);
	for(int i=0;i<lim;++i) rev[i]=rev[i>>1]>>1|(i&1)<<(len-1);
	for(int i=0;i<lim;++i)if(i<rev[i]) swap(F[i],F[rev[i]]);
	for(int i=1;i<lim;i<<=1)
		for(int j=0;j<lim;j+=i<<1)for(int k=0;k<i;++k){
			int t=mul(omg[dir][N/(i<<1)*k],F[j+i+k]);
			F[j+i+k]=add(F[j+k],mod-t),F[j+k]=add(F[j+k],t);
		}
	if(dir==1){
		int ilim=fpow(lim,mod-2);
		for(int i=0;i<lim;++i) F[i]=mul(F[i],ilim);
	}
}
poly operator~(poly F){
	int n=F.size();
	poly G={fpow(F[0],mod-2)};
	F.resize(1<<(int)ceil(log2(n)));
	for(int lim=2;lim<2*n;lim<<=1){
		poly H(F.begin(),F.begin()+lim);
		H.resize(lim<<1),NTT(H,0);
		G.resize(lim<<1),NTT(G,0);
		for(int i=0;i<lim<<1;++i) G[i]=mul(2+mod-mul(H[i],G[i]),G[i]);
		NTT(G,1),G.resize(lim);
	}
	return G.resize(n),G;
}
poly log(poly F){
	int n=F.size();
	poly G=~F;
	for(int i=0;i<n-1;++i) F[i]=mul(F[i+1],i+1);
	F.resize(n-1);
	int lim=1<<(int)ceil(log2(2*n-2));
	F.resize(lim),NTT(F,0);
	G.resize(lim),NTT(G,0);
	for(int i=0;i<lim;++i) F[i]=mul(F[i],G[i]);
	NTT(F,1),F.resize(n);
	for(int i=n-1;i>=1;--i) F[i]=mul(F[i-1],inv[i]);
	return F[0]=0,F;
}
poly exp(poly F){
	int n=F.size();
	poly G={1};
	F.resize(1<<(int)ceil(log2(n)));
	for(int lim=2;lim<2*n;lim<<=1){
		G.resize(lim);poly H=log(G);
		H[0]=add(1+F[0],mod-H[0]);
		for(int i=1;i<lim;++i) H[i]=add(F[i],mod-H[i]);
		H.resize(lim<<1),NTT(H,0);
		G.resize(lim<<1),NTT(G,0);
		for(int i=0;i<lim<<1;++i) G[i]=mul(H[i],G[i]);
		NTT(G,1),G.resize(lim);
	}
	return G.resize(n),G;
}

int main(){
	omg[0][0]=1,omg[0][1]=fpow(3,(mod-1)/N);
	omg[1][0]=1,omg[1][1]=fpow(omg[0][1],mod-2);
	fac[0]=fac[1]=1;
	inv[0]=inv[1]=1;
	ifac[0]=ifac[1]=1;
	for(int i=2;i<N;++i){
		omg[0][i]=mul(omg[0][i-1],omg[0][1]);
		omg[1][i]=mul(omg[1][i-1],omg[1][1]);
		fac[i]=mul(fac[i-1],i);
		inv[i]=mul(mod-mod/i,inv[mod%i]);
		ifac[i]=mul(ifac[i-1],inv[i]);
	}
	int n=1e5;
	poly B(n+1);
	for(int i=1;i<=n;++i) B[i]=ifac[i];
	B=exp(B);
	for(int i=1;i<=n;++i) B[i]=mul(B[i],fac[i]);
	for(int T=read<int>();T--;) printf("%d\n",B[read<int>()]);
	return 0;
}

整数划分计数

https://loj.ac/problem/6268
https://blog.csdn.net/qq_39972971/article/details/88684362

\[D(x)=\prod_{i=1}^{\infty}\frac{1}{1-x^i} \]

对等式两侧取对数,有

\[\ln(D(x))=\sum_{i=1}^{\infty}\ln(\frac{1}{1-x^i}) \]

因为

\[\ln(\frac{1}{1-x^i})=\sum_{j=1}^{\infty}\frac{(x^i)^j}{j} \]

所以

\[\ln(D(x))=\sum_{i=1}^{\infty}\sum_{j=1}^{\infty}\frac{(x^i)^j}{j} \]

\(O(n\ln n)\)的时间求出\(\ln(D(x))\)的前\(n\)项,然后\(\exp\)就行了。时间复杂度\(O(n\log n)\)

CO int N=1<<18;
int omg[2][N],rev[N];
int fac[N],inv[N],ifac[N];

void NTT(poly&F,int dir){
	int lim=F.size(),len=log2(lim);
	for(int i=0;i<lim;++i) rev[i]=rev[i>>1]>>1|(i&1)<<(len-1);
	for(int i=0;i<lim;++i)if(i<rev[i]) swap(F[i],F[rev[i]]);
	for(int i=1;i<lim;i<<=1)
		for(int j=0;j<lim;j+=i<<1)for(int k=0;k<i;++k){
			int t=mul(omg[dir][N/(i<<1)*k],F[j+i+k]);
			F[j+i+k]=add(F[j+k],mod-t),F[j+k]=add(F[j+k],t);
		}
	if(dir==1){
		int ilim=fpow(lim,mod-2);
		for(int i=0;i<lim;++i) F[i]=mul(F[i],ilim);
	}
}
poly operator~(poly F){
	int n=F.size();
	poly G={fpow(F[0],mod-2)};
	F.resize(1<<(int)ceil(log2(n)));
	for(int lim=2;lim<2*n;lim<<=1){
		poly H(F.begin(),F.begin()+lim);
		H.resize(lim<<1),NTT(H,0);
		G.resize(lim<<1),NTT(G,0);
		for(int i=0;i<lim<<1;++i) G[i]=mul(2+mod-mul(H[i],G[i]),G[i]);
		NTT(G,1),G.resize(lim);
	}
	return G.resize(n),G;
}
poly log(poly F){
	int n=F.size();
	poly G=~F;
	for(int i=0;i<n-1;++i) F[i]=mul(F[i+1],i+1);
	F.resize(n-1);
	int lim=1<<(int)ceil(log2(2*n-2));
	F.resize(lim),NTT(F,0);
	G.resize(lim),NTT(G,0);
	for(int i=0;i<lim;++i) F[i]=mul(F[i],G[i]);
	NTT(F,1),F.resize(n);
	for(int i=n-1;i>=1;--i) F[i]=mul(F[i-1],inv[i]);
	return F[0]=0,F;
}
poly exp(poly F){
	int n=F.size();
	poly G={1};
	F.resize(1<<(int)ceil(log2(n)));
	for(int lim=2;lim<2*n;lim<<=1){
		G.resize(lim);poly H=log(G);
		H[0]=add(1+F[0],mod-H[0]);
		for(int i=1;i<lim;++i) H[i]=add(F[i],mod-H[i]);
		H.resize(lim<<1),NTT(H,0);
		G.resize(lim<<1),NTT(G,0);
		for(int i=0;i<lim<<1;++i) G[i]=mul(H[i],G[i]);
		NTT(G,1),G.resize(lim);
	}
	return G.resize(n),G;
}

int main(){
	omg[0][0]=1,omg[0][1]=fpow(3,(mod-1)/N);
	omg[1][0]=1,omg[1][1]=fpow(omg[0][1],mod-2);
	fac[0]=fac[1]=1;
	inv[0]=inv[1]=1;
	ifac[0]=ifac[1]=1;
	for(int i=2;i<N;++i){
		omg[0][i]=mul(omg[0][i-1],omg[0][1]);
		omg[1][i]=mul(omg[1][i-1],omg[1][1]);
		fac[i]=mul(fac[i-1],i);
		inv[i]=mul(mod-mod/i,inv[mod%i]);
		ifac[i]=mul(ifac[i-1],inv[i]);
	}
	int n=read<int>();
	poly D(n+1);
	for(int i=1;i<=n;++i)for(int j=i;j<=n;j+=i)
		D[j]=add(D[j],inv[i]);
	D=exp(D);
	for(int i=1;i<=n;++i) printf("%d\n",D[i]);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/12961179.html