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


    集合划分计数

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

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

    时间复杂度(O(nlog 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
    ",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(nln n))的时间求出(ln(D(x)))的前(n)项,然后(exp)就行了。时间复杂度(O(nlog 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
    ",D[i]);
    	return 0;
    }
    
  • 相关阅读:
    CREATE OPERATOR
    create_module
    一个LINUX狂人的语录(个人认为很精辟)
    jQuery 判断多个 input file 都不能为空
    Java实现 LeetCode 2 两数相加
    Java实现 LeetCode 2 两数相加
    Java实现 LeetCode 2 两数相加
    Java实现 蓝桥杯 算法提高 和谐宿舍2
    Java实现 蓝桥杯 算法提高 和谐宿舍2
    Java实现 蓝桥杯 算法提高 和谐宿舍2
  • 原文地址:https://www.cnblogs.com/autoint/p/12961179.html
Copyright © 2020-2023  润新知