斯特林数的四种求法
一、第一类斯特林数求行
因为
[x^{overline{n}}=sum_{i=0}^{n}left[egin{matrix}n\iend{matrix}
ight]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
]
那么
[egin{aligned}
f(x+c)&=sum_{i=0}^{n}a_i(x+c)^i\
&=sum_{i=0}^{n}a_isum_{j=0}^{i}inom ijx^jc^{i-j}\
&=sum_{j=0}^{n}x^jsum_{i=j}^{n}a_iinom 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{egin{matrix}n\mend{matrix}
ight}=dfrac{1}{m!}sum_{k=0}^{m}(-1)^kinom{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;
}