斯特林数的四种求法
斯特林数的四种求法
一、第一类斯特林数求行
因为
\[x^{\overline{n}}=\sum_{i=0}^{n}\left[\begin{matrix}n\\i\end{matrix}\right]x^i
\]
所以只要求出\(x^{\overline{n}}\)的系数就能求出第一类斯特林数的一行,那么如何求解\(x^{\overline{n}}\)呢?
注意到\(x^{\overline{2n}}=x^{\overline{n}}(x+n)^{\overline{n}}\),因此只要我们能够在已知\(f(x)\)的情况下快速求解\(f(x+n)\),那么就可以通过\(\mathcal O(nlog(n))\)完成。
不妨设
\[f(x)=\sum_{i=0}^{n}a_ix^i
\]
那么
\[\begin{aligned}
f(x+c)&=\sum_{i=0}^{n}a_i(x+c)^i\\
&=\sum_{i=0}^{n}a_i\sum_{j=0}^{i}\binom ijx^jc^{i-j}\\
&=\sum_{j=0}^{n}x^j\sum_{i=j}^{n}a_i\binom ij c^{i-j}\\
&=\sum_{j=0}^{n}\dfrac{x^j}{j!}\sum_{i=j}^{n}a_ii!\dfrac{c^{i-j}}{(i-j)!}
\end{aligned}
\]
后面是一个减法卷积的形式了,于是可以\(\mathcal O(nlog(n))\)快速求解。
#include "poly.cpp"
inline poly trans(poly f,int n,int c){
init_inv(n);
poly g;int t=1;
for(int i=0;i<n;t=1ll*t*c%mod,++i) f[i]=1ll*base[i]*f[i]%mod,g[i]=1ll*t*jc[i]%mod;
reverse(f.v.begin(),f.v.begin()+n);
poly h=Basic::mul(f,g,n,n),ret;
for(int i=0;i<n;++i) ret[i]=1ll*h[n-1-i]*jc[i]%mod;
return ret;
}
inline poly solve(int l,int r){
if(l>r) return poly(1);
if(l==r){poly g;g[1]=1;g[0]=l;return g;}
int len=r-l+1,mid=(l+r)>>1;
if(len&1) return Basic::mul(solve(l,mid),solve(mid+1,r),mid-l+2,r-mid+1);
else{
poly g=solve(l,mid),h=trans(g,mid-l+2,len/2);
return Basic::mul(g,h,mid-l+2,r-mid+1);
}
}
int main(){
// freopen("poly.in","r",stdin);
int n=Rint;
init_poly((n+1)<<1);
solve(0,n-1).print(n+1);
IO::flush();
return 0;
}
二、第二类斯特林数求行
利用通项公式直接求解即可。
\[\left\{\begin{matrix}n\\m\end{matrix}\right\}=\dfrac{1}{m!}\sum_{k=0}^{m}(-1)^k\binom{m}{k}(m-k)^n
\]
#include "poly.cpp"
int n,m;
poly f,g;
int main(){
// freopen("poly.in","r",stdin);
n=Rint;
init_poly((n+1)<<1);
init_inv(n+1);
for(int i=0;i<=n;++i){
f[i]=1ll*jc[i]*(i&1?mod-1:1)%mod;
g[i]=1ll*ksm(i,n)*jc[i]%mod;
}
f=Basic::mul(f,g,n+1,n+1);f.print(n+1);
IO::flush();
return 0;
}
三、第一类斯特林数求列
一个环的EGF为
\[F(x)=\sum_{i=1} \dfrac{(i-1)!}{i!}x^i=\ln(\frac{1}{1-x})
\]
于是答案的EGF就是:
\[\frac{F(x)^k}{k!}
\]
除\(x!\)是因为集合是无序的,而\(k\)次方把它当成了有序。
#include "poly.cpp"
int n,k,base[N],ivk;
poly f;
int main(){
scanf("%d%d",&n,&k);
if(n<k){for(int i=0;i<=n;++i) pc('0'),pc(' ');IO::flush();return 0;}
init_inv(n+1);
init_poly(n+1);
base[0]=1;
for(int i=1;i<=n;++i) base[i]=1ll*base[i-1]*i%mod;
int ivk=ksm(base[k],mod-2);
for(int i=1;i<=n;++i) f[i-1]=iv[i];
f=Exp::getpow(f,n,k);
for(int i=0;i<k;++i) pc('0'),pc(' ');
for(int i=k,j=0;i<=n;++i,++j)
put(1ll*f[j]*base[i]%mod*ivk%mod,' ');
IO::flush();
return 0;
}
四、第二类斯特林数求列
一个集合的EGF为:
\[\sum_{i=1}\frac{1}{i!}x^i=e^x-1
\]
于是同理多项式快速幂即可。
#include "poly.cpp"
int n,k,base[N],jc[N],ivk;
poly f;
int main(){
scanf("%d%d",&n,&k);
if(n<k){for(int i=0;i<=n;++i) pc('0'),pc(' ');IO::flush();return 0;}
init_inv(n+1);
init_poly(n+1);
base[0]=1;jc[0]=1;
for(int i=1;i<=n;++i) base[i]=1ll*base[i-1]*i%mod,jc[i]=1ll*jc[i-1]*iv[i]%mod;
int ivk=ksm(base[k],mod-2);
for(int i=1;i<=n;++i) f[i-1]=jc[i];
f=Exp::getpow(f,n-k+1,k);
for(int i=0;i<k;++i) pc('0'),pc(' ');
for(int i=k,j=0;i<=n;++i,++j)
put(1ll*f[j]*base[i]%mod*ivk%mod,' ');
IO::flush();
return 0;
}

浙公网安备 33010602011771号