集合划分计数和整数划分计数
集合划分计数
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;
}
静渊以有谋,疏通而知事。