斯特林数的四种求法

斯特林数的四种求法

一、第一类斯特林数求行

因为

[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;
}
原文地址:https://www.cnblogs.com/tqxboomzero/p/14593272.html