组合数学

本文深入探讨了斯特林数的两大类:第一类斯特林数和第二类斯特林数,包括它们的递推公式、性质、与乘方及幂次运算的关系,以及在组合数学中的应用。文章还提供了求解特定行斯特林数的高效算法。

斯特林数

(一)第一类斯特林数

s1(n,m)s1(n,m)s1(n,m)表示n个元素排成m个圆排列的个数,记作[nm]n \brack m[mn]

a.递推公式与性质

[nm]=[n−1m−1]+[n−1m]∗(n−1){n\brack m}={n-1\brack m-1}+{n-1\brack m}*(n-1)[mn]=[m1n1]+[mn1](n1)

​ 新来的元素既可以自己成为一个圆排列,又可以放在任意一个已有元素的后面。

b.和乘方&下降幂的关系、和乘方&上升幂的关系

nk‾=∑i=0k[ki]∗(−1)k−i∗nin^{\underline k}=\sum^k_{i=0}{k\brack i}*(-1)^{k-i}*n^ink=i=0k[ik](1)kini

KaTeX parse error: Got function '\overline' with no arguments as superscript at position 3: n^\̲o̲v̲e̲r̲l̲i̲n̲e̲ ̲k=\sum^k_{i=0}{…

证明1:(数学归纳法)

当k=0时显然成立,当k>0时

KaTeX parse error: Got function '\underline' with no arguments as superscript at position 3: n^\̲u̲n̲d̲e̲r̲l̲i̲n̲e̲ ̲k=(n-k+1)*n^\un…

=(n−k+1)∗∑i=0k−1[k−1i]∗(−1)k−1−i∗ni=(n-k+1)*\sum^{k-1}_{i=0}{k-1\brack i}*(-1)^{k-1-i}*n^i=(nk+1)i=0k1[ik1](1)k1ini

=n∗∑i=0k−1[k−1i]∗(−1)k−1−i∗ni−(k−1)∗∑i=0k−1[k−1i]∗(−1)k−1−i∗ni=n*\sum^{k-1}_{i=0}{k-1\brack i}*(-1)^{k-1-i}*n^i-(k-1)*\sum^{k-1}_{i=0}{k-1\brack i}*(-1)^{k-1-i}*n^i=ni=0k1[ik1](1)k1ini(k1)i=0k1[ik1](1)k1ini

=n∗∑i=1k[k−1i−1]∗(−1)k−i∗ni−1−(k−1)∗∑i=0k−1[k−1i]∗(−1)k−1−i∗ni=n*\sum^{k}_{i=1}{k-1\brack i-1}*(-1)^{k-i}*n^{i-1}-(k-1)*\sum^{k-1}_{i=0}{k-1\brack i}*(-1)^{k-1-i}*n^i=ni=1k[i1k1](1)kini1(k1)i=0k1[ik1](1)k1ini

=∑i=1k[k−1i−1]∗(−1)k−i∗ni−∑i=1k(k−1)∗[k−1i]∗(−1)k−1−i∗ni=\sum^{k}_{i=1}{k-1\brack i-1}*(-1)^{k-i}*n^i-\sum^{k}_{i=1}(k-1)*{k-1\brack i}*(-1)^{k-1-i}*n^i=i=1k[i1k1](1)kinii=1k(k1)[ik1](1)k1ini //注意i=0时若k=1则k−1=0k-1=0k1=0,否则[k−1i]=0{k-1\brack i}=0[ik1]=0;i=k时[k−1i]=0{k-1\brack i}=0[ik1]=0

=∑i=1k[k−1i−1]∗(−1)k−i∗ni+∑i=1k(k−1)∗[k−1i]∗(−1)k−i∗ni=\sum^{k}_{i=1}{k-1\brack i-1}*(-1)^{k-i}*n^i+\sum^{k}_{i=1}(k-1)*{k-1\brack i}*(-1)^{k-i}*n^i=i=1k[i1k1](1)kini+i=1k(k1)[ik1](1)kini

=∑i=1k([k−1i−1]+(k−1)∗[k−1i])∗(−1)k−i∗ni=\sum^{k}_{i=1}({k-1\brack i-1}+(k-1)*{k-1\brack i})*(-1)^{k-i}*n^i=i=1k([i1k1]+(k1)[ik1])(1)kini

=∑i=0k[ki]∗(−1)k−i∗ni=\sum^k_{i=0}{k\brack i}*(-1)^{k-i}*n^i=i=0k[ik](1)kini

证明2:(数学归纳法)(类似的就不写那么详细了)

当k=0时显然成立,当k>0时

KaTeX parse error: Got function '\overline' with no arguments as superscript at position 3: n^\̲o̲v̲e̲r̲l̲i̲n̲e̲ ̲k=(n+k-1)*n^\ov…

=(n+k−1)∗∑i=0k−1[k−1i]∗ni=(n+k-1)*\sum^{k-1}_{i=0}{k-1\brack i}*n^i=(n+k1)i=0k1[ik1]ni

=∑i=1k∗[k−1i−1]∗ni+∑i=1k[k−1i]∗(k−1)∗ni=\sum^k_{i=1}*{k-1\brack i-1}*n^i+\sum^{k}_{i=1}{k-1\brack i}*(k-1)*n^i=i=1k[i1k1]ni+i=1k[ik1](k1)ni

=∑i=0k[ki]∗ni=\sum^k_{i=0}{k\brack i}*n^i=i=0k[ik]ni

现实意义:将下降幂用n^i展开,其系数绝对值为第一类斯特林数,且正负性交错,而将上升幂展开,其系数即为第一类斯特林数

c.求第n行的第一类斯特林数

为了方便用上升幂的柿子来求。柿子本来是这样的KaTeX parse error: Got function '\overline' with no arguments as superscript at position 3: n^\̲o̲v̲e̲r̲l̲i̲n̲e̲ ̲k=\prod^{n+k-1}…,但因为要算第n行,变成这样KaTeX parse error: Got function '\overline' with no arguments as superscript at position 3: x^\̲o̲v̲e̲r̲l̲i̲n̲e̲ ̲n=\prod^{n-1}_{…,其中x是一个未知数

注意到上升幂展开,其系数即为第一类斯特林数,换言之就是要把第二个柿子的每个数看成一个多项式乘起来,最后的系数就是答案。nice可以做到O(n2logn)O(n^2logn)O(n2logn)啦。下面就不用看了

用脑子考虑分治,多项式初始长度为2,合并一次长度翻倍

T(n)=2T(n2)+O(nlogn)T(n)=2T({n\over 2})+O(nlogn)T(n)=2T(2n)+O(nlogn) 所以时间复杂度为O(nlog2n)O(nlog^2n)O(nlog2n)

进一步优化

因为KaTeX parse error: Got function '\overline' with no arguments as superscript at position 3: x^\̲o̲v̲e̲r̲l̲i̲n̲e̲ ̲{2n}=(\prod^{n-…,如果能够通过∏i=0n−1x+i\prod^{n-1}_{i=0}x+ii=0n1x+i得到∏i=0n−1x+n+i\prod^{n-1}_{i=0}x+n+ii=0n1x+n+i(这东西=KaTeX parse error: Got function '\overline' with no arguments as superscript at position 8: =(x+n)^\̲o̲v̲e̲r̲l̲i̲n̲e̲ ̲n),则T(n)=T(n2)+O(nlogn)T(n)=T({n\over 2})+O(nlogn)T(n)=T(2n)+O(nlogn) 时间复杂度O(nlogn)O(nlogn)O(nlogn)

我们设前者得到的多项式f(x)=∑i=0L−1ai∗xif(x)=\sum^{L-1}_{i=0} ai*x^if(x)=i=0L1aixi,则多项式f(x+n)=∑i=0L−1ai∗(x+n)if(x+n)=\sum^{L-1}_{i=0} ai*(x+n)^if(x+n)=i=0L1ai(x+n)i即为所求

f(x+n)=∑i=0L−1ai∗(x+n)i=∑i=0L−1ai∗∑j=0i(ij)∗ni−j∗xjf(x+n)=\sum^{L-1}_{i=0} a_i*(x+n)^i=\sum^{L-1}_{i=0} a_i*\sum^i_{j=0}{i\choose j}*n^{i-j}*x^jf(x+n)=i=0L1ai(x+n)i=i=0L1aij=0i(ji)nijxj //二项式展开

=∑i=0L−1(∑j=iL−1(ji)∗nj−i∗aj)∗xi=\sum^{L-1}_{i=0}(\sum^{L-1}_{j=i}{j\choose i}*n^{j-i}*a_j)*x^i=i=0L1(j=iL1(ij)njiaj)xi

问题在如何处理出ci=∑j=iL−1(ji)∗nj−i∗ajc_i=\sum^{L-1}_{j=i}{j\choose i}*n^{j-i}*a_jci=j=iL1(ij)njiaj

=1i!∑j=iL−1j!(j−i)!∗nj−i∗aj={1\over i!}\sum^{L-1}_{j=i}{j!\over (j-i)!}*n^{j-i}*a_j=i!1j=iL1(ji)!j!njiaj

g(j)=j!∗aj,h(j)=njj!且当j≤0时=0g(j)=j!*a_j,h(j)={n^{j}\over j!}且当j\leq0时=0g(j)=j!aj,h(j)=j!njj0=0

=1i!∑j=0L−1g(j)∗h(j−i)={1\over i!}\sum^{L-1}_{j=0}g(j)*h(j-i)=i!1j=0L1g(j)h(ji)

事实上这已经是一个经典问题了,但是我忘了,所以再推一遍:

不希望h的定义域有负数,人为向右移L位:=1i!∑j=0L−1g(j)∗h(j−i+L)={1\over i!}\sum^{L-1}_{j=0}g(j)*h(j-i+L)=i!1j=0L1g(j)h(ji+L)

把总长为2L的h反过来:=1i!∑j=0L−1g(j)∗h(i−j+L−1)={1\over i!}\sum^{L-1}_{j=0}g(j)*h(i-j+L-1)=i!1j=0L1g(j)h(ij+L1)

就这样卷积完以后,再左移L-1位就可以了

总的实现思路:

1:递归求解KaTeX parse error: Got function '\overline' with no arguments as superscript at position 3: x^\̲o̲v̲e̲r̲l̲i̲n̲e̲ ̲{\lfloor{n\over…的多项式

2:通过KaTeX parse error: Got function '\overline' with no arguments as superscript at position 3: x^\̲o̲v̲e̲r̲l̲i̲n̲e̲ ̲{\lfloor{n\over…的多项式得到KaTeX parse error: Got function '\overline' with no arguments as superscript at position 16: (x+{n\over 2})^\̲o̲v̲e̲r̲l̲i̲n̲e̲ ̲{\lfloor{n\over…的多项式

3:两式相乘得到KaTeX parse error: Got function '\overline' with no arguments as superscript at position 3: x^\̲o̲v̲e̲r̲l̲i̲n̲e̲{\lfloor{n\over…

4:若n为奇数,再乘上x+n

我的代码遇上卡常的基本过不去

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int _=1e2;
const int maxn=(1<<18)+_;
const int mod=167772161;
inline int ad(int x,int y){return x>=mod-y?x-mod+y:x+y;}
inline int re(int x,int y){return x<y?x-y+mod:x-y;}
inline int mu(int x,int y){return (LL)x*y%mod;}
inline int qp(int x,int y){int r=1;while(y){if(y&1)r=mu(r,x);x=mu(x,x),y>>=1;}return r;}
inline int dv(int x,int y){return mu(x,qp(y,mod-2));}

int fac[2*maxn],fac_inv[2*maxn];
void yu()
{
	fac[0]=1;
	for(int i=1;i<2*maxn;i++)fac[i]=mu(i,fac[i-1]);
	fac_inv[2*maxn-1]=qp(fac[2*maxn-1],mod-2);
	for(int i=2*maxn-2;i>=0;i--)fac_inv[i]=mu(fac_inv[i+1],i+1);
}

namespace J
{
	int Re[4*maxn];
	void NTT(int *a,int n,int op)
	{
		for(int i=0;i<n;i++)
			if(i<Re[i])swap(a[i],a[Re[i]]);
		
		for(int i=1;i<n;i<<=1)
		{
			int gn=qp(3,(mod-1)/(i<<1));
			if(op==-1)gn=qp(gn,mod-2);
			for(int j=0;j<n;j+=(i<<1))
			{
				int g=1;
				for(int k=0;k<i;k++,g=mu(g,gn))
				{
					int k1=a[j+k],k2=mu(a[j+k+i],g);
					a[j+k]=ad(k1,k2);
					a[j+k+i]=re(k1,k2);
				}
			}
		}
		if(op==-1)
		{
			int inv=qp(n,mod-2);
			for(int i=0;i<n;i++)a[i]=mu(a[i],inv);
		}
	}
	int n,m,L,A[4*maxn],B[4*maxn]; 
	void main()
	{
		int tn=n,tm=m;
		m=n+m-1;for(n=1,L=0;n<=m;n<<=1)L++;
		for(int i=0;i<n;i++)Re[i]=(Re[i>>1]>>1)|((i&1)<<(L-1));
		for(int i=tn;i<n;i++)A[i]=0;
		for(int i=tm;i<n;i++)B[i]=0;
		NTT(A,n,1),NTT(B,n,1);
		for(int i=0;i<n;i++)A[i]=mu(A[i],B[i]);
		NTT(A,n,-1);
	}
}using namespace J;

int len,a[2*maxn],b[4*maxn];
void solve(int n)
{
	if(n==1){len=2,a[1]=1;return ;}
	solve(n/2);
	
	J::n=len,J::m=2*len;
	for(int i=0,t=1;i<len;i++,t=mu(t,n/2))
		A[i]=mu(fac[i],a[i]),B[i]=0,B[i+len]=mu(t,fac_inv[i]);
	reverse(B,B+2*len);
	J::main();
	for(int i=0;i<len;i++)b[i]=mu(A[i+len-1],fac_inv[i]);
	
	J::n=len,J::m=len;
	for(int i=0;i<len;i++)
		A[i]=a[i],B[i]=b[i];
	J::main();
	len=J::m;
	for(int i=0;i<len;i++)a[i]=A[i];
	
	
	if(n&1)
	{
		for(int i=0;i<len;i++)b[i]=mu(a[i],n-1); b[len+1]=0;
		for(int i=len;i>=1;i--)a[i]=a[i-1]; a[0]=0;
		len++;
		for(int i=0;i<len;i++)a[i]=ad(a[i],b[i]);
	}
}

int main()
{
	int n;
	scanf("%d",&n); yu();
	solve(n);
	for(int i=0;i<=n;i++)printf("%d ",a[i]);
	
	return 0;
}
(二)第二类斯特林数

s2(n,m)s2(n,m)s2(n,m)表示n个元素划分到m个集合的方案数,记作{nm}n\brace m{mn}

a.递推公式与性质

{nm}={n−1m−1}+{n−1m}∗m{n\brace m}={n-1\brace m-1}+{n-1\brace m}*m{mn}={m1n1}+{mn1}m

​ 新来的元素可以自己成为一个集合,或者放到任意一个已有集合里

b.和乘方&下降幂的关系、和乘方&上升幂的关系

KaTeX parse error: Got function '\underline' with no arguments as superscript at position 31: …}{k\brace i}*n^\̲u̲n̲d̲e̲r̲l̲i̲n̲e̲ ̲i 也可写作nk=∑i=0m{ki}∗i!∗(ni)n^k=\sum^m_{i=0}{k\brace i}*i!*{n\choose i}nk=i=0m{ik}i!(in)

KaTeX parse error: Got function '\overline' with no arguments as superscript at position 42: …}*(-1)^{k-i}*n^\̲o̲v̲e̲r̲l̲i̲n̲e̲ ̲i

证明1:(数学归纳法)

当k=0时显然成立,当k>0时

nkn^knk=n(k−1)∗nn^{(k-1)}*nn(k1)n

KaTeX parse error: Got function '\underline' with no arguments as superscript at position 36: …k-1\brace i}*n^\̲u̲n̲d̲e̲r̲l̲i̲n̲e̲ ̲i*(n-i+i)

KaTeX parse error: Got function '\underline' with no arguments as superscript at position 37: …-1\brace i}*(n^\̲u̲n̲d̲e̲r̲l̲i̲n̲e̲ ̲{i+1}+i*n^\unde…

KaTeX parse error: Got function '\underline' with no arguments as superscript at position 36: …k-1\brace i}*n^\̲u̲n̲d̲e̲r̲l̲i̲n̲e̲ ̲{i+1}+\sum^{(k-…

KaTeX parse error: Got function '\underline' with no arguments as superscript at position 34: …1\brace i-1}*n^\̲u̲n̲d̲e̲r̲l̲i̲n̲e̲ ̲i+\sum^{k}_{i=1… //注意i=0时i=0i=0i=0,i=k时{k−1i}=0{k-1\brace i}=0{ik1}=0

KaTeX parse error: Got function '\underline' with no arguments as superscript at position 18: …sum^{k}_{i=1}n^\̲u̲n̲d̲e̲r̲l̲i̲n̲e̲ ̲i*({k-1\brace i…

KaTeX parse error: Got function '\underline' with no arguments as superscript at position 18: …sum^{k}_{i=0}n^\̲u̲n̲d̲e̲r̲l̲i̲n̲e̲ ̲i*{k\brace i} //注意i=0且k>0时{ki}=0{k\brace i}=0{ik}=0

从组合意义理解nk=∑i=0n{ki}∗i!∗(ni)n^k=\sum^n_{i=0}{k\brace i}*i!*{n\choose i}nk=i=0n{ik}i!(in)

​ 左边:k个球放进n个有序盒子,随便放

​ 右边:选i个盒子出来放,把盒子当集合把球划分,实际上盒子有序,再乘i!

证明2:(数学归纳法)(同样类似)

当k=0时显然成立,当k>0时

nkn^knk=n(k−1)∗nn^{(k-1)}*nn(k1)n

KaTeX parse error: Got function '\overline' with no arguments as superscript at position 49: …(-1)^{k-1-i}*n^\̲o̲v̲e̲r̲l̲i̲n̲e̲ ̲i*(n+i-i)

KaTeX parse error: Got function '\overline' with no arguments as superscript at position 45: …}*(-1)^{k-i}*n^\̲o̲v̲e̲r̲l̲i̲n̲e̲ ̲i-\sum^{k}_{i=1…

KaTeX parse error: Got function '\overline' with no arguments as superscript at position 39: …}*(-1)^{k-i}*n^\̲o̲v̲e̲r̲l̲i̲n̲e̲ ̲i

c.求第n行的第二类斯特林数

{nm}=1m!∑i=0m(−1)(m−i)∗(mi)∗mn{n\brace m}={1\over m!}\sum^m_{i=0}(-1)^{(m-i)}*{m\choose i}*m^n{mn}=m!1i=0m(1)(mi)(im)mn n是常数,(−1)(m−i)(-1)^{(m-i)}(1)(mi)(mi){m\choose i}(im)分别弄一个多项式然后FFT卷起来即可

证明(利用广义容斥原理)

​ 令f(m)={nm}∗m!f(m)={n\brace m}*m!f(m)={mn}m! 意为把n个球放恰好m个有序盒子的方案数

​ 令g(m)=mng(m)=m^ng(m)=mn 意为把n个球放至多m个有序盒子中

​ 则g(m)=∑i=0mh(i)f(i)g(m)=\sum^m_{i=0} h(i)f(i)g(m)=i=0mh(i)f(i),考虑容斥系数,对于计算g(j)时f(i)对g(j)的贡献次数,i个盒子可以按顺序放在总共j个位置中的不同位置,即组合数,哦,原来是二项式反演啊

​ 则g(m)=∑i=0m(mi)f(i)g(m)=\sum^m_{i=0} {m \choose i}f(i)g(m)=i=0m(im)f(i)

​ 则f(m)=∑i=0m(−1)(m−i)∗(mi)∗g(i)f(m)=\sum^m_{i=0}(-1)^{(m-i)}*{m\choose i}*g(i)f(m)=i=0m(1)(mi)(im)g(i)

​ 即{nm}∗m!=∑i=0m(−1)(m−i)∗{mi}∗mn{n\brace m}*m!=\sum^m_{i=0}(-1)^{(m-i)}*{m\brace i}*m^n{mn}m!=i=0m(1)(mi){im}mn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值