组合数学

斯特林数

(一)第一类斯特林数

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

a.递推公式与性质

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

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

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

n k ‾ = ∑ i = 0 k [ k i ] ∗ ( − 1 ) k − i ∗ n i n^{\underline k}=\sum^k_{i=0}{k\brack i}*(-1)^{k-i}*n^i nk=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 = 0 k − 1 [ k − 1 i ] ∗ ( − 1 ) k − 1 − i ∗ n i =(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 = 0 k − 1 [ k − 1 i ] ∗ ( − 1 ) k − 1 − i ∗ n i − ( k − 1 ) ∗ ∑ i = 0 k − 1 [ k − 1 i ] ∗ ( − 1 ) k − 1 − i ∗ n i =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 = 1 k [ k − 1 i − 1 ] ∗ ( − 1 ) k − i ∗ n i − 1 − ( k − 1 ) ∗ ∑ i = 0 k − 1 [ k − 1 i ] ∗ ( − 1 ) k − 1 − i ∗ n i =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 = 1 k [ k − 1 i − 1 ] ∗ ( − 1 ) k − i ∗ n i − ∑ i = 1 k ( k − 1 ) ∗ [ k − 1 i ] ∗ ( − 1 ) k − 1 − i ∗ n i =\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 = 0 k-1=0 k1=0,否则 [ k − 1 i ] = 0 {k-1\brack i}=0 [ik1]=0;i=k时 [ k − 1 i ] = 0 {k-1\brack i}=0 [ik1]=0

= ∑ i = 1 k [ k − 1 i − 1 ] ∗ ( − 1 ) k − i ∗ n i + ∑ i = 1 k ( k − 1 ) ∗ [ k − 1 i ] ∗ ( − 1 ) k − i ∗ n i =\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 = 1 k ( [ k − 1 i − 1 ] + ( k − 1 ) ∗ [ k − 1 i ] ) ∗ ( − 1 ) k − i ∗ n i =\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 = 0 k [ k i ] ∗ ( − 1 ) k − i ∗ n i =\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 = 0 k − 1 [ k − 1 i ] ∗ n i =(n+k-1)*\sum^{k-1}_{i=0}{k-1\brack i}*n^i =(n+k1)i=0k1[ik1]ni

= ∑ i = 1 k ∗ [ k − 1 i − 1 ] ∗ n i + ∑ i = 1 k [ k − 1 i ] ∗ ( k − 1 ) ∗ n i =\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 = 0 k [ k i ] ∗ n i =\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 ( n 2 l o g n ) O(n^2logn) O(n2logn)啦。下面就不用看了

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

T ( n ) = 2 T ( n 2 ) + O ( n l o g n ) T(n)=2T({n\over 2})+O(nlogn) T(n)=2T(2n)+O(nlogn) 所以时间复杂度为 O ( n l o g 2 n ) 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 = 0 n − 1 x + i \prod^{n-1}_{i=0}x+i i=0n1x+i得到 ∏ i = 0 n − 1 x + n + i \prod^{n-1}_{i=0}x+n+i i=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 ( n 2 ) + O ( n l o g n ) T(n)=T({n\over 2})+O(nlogn) T(n)=T(2n)+O(nlogn) 时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

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

f ( x + n ) = ∑ i = 0 L − 1 a i ∗ ( x + n ) i = ∑ i = 0 L − 1 a i ∗ ∑ j = 0 i ( i j ) ∗ n i − j ∗ x j f(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^j f(x+n)=i=0L1ai(x+n)i=i=0L1aij=0i(ji)nijxj //二项式展开

= ∑ i = 0 L − 1 ( ∑ j = i L − 1 ( j i ) ∗ n j − i ∗ a j ) ∗ x i =\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

问题在如何处理出 c i = ∑ j = i L − 1 ( j i ) ∗ n j − i ∗ a j c_i=\sum^{L-1}_{j=i}{j\choose i}*n^{j-i}*a_j ci=j=iL1(ij)njiaj

= 1 i ! ∑ j = i L − 1 j ! ( j − i ) ! ∗ n j − i ∗ a j ={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 ! ∗ a j , h ( j ) = n j j ! 且 当 j ≤ 0 时 = 0 g(j)=j!*a_j,h(j)={n^{j}\over j!}且当j\leq0时=0 g(j)=j!aj,h(j)=j!njj0=0

= 1 i ! ∑ j = 0 L − 1 g ( 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位: = 1 i ! ∑ j = 0 L − 1 g ( 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反过来: = 1 i ! ∑ j = 0 L − 1 g ( 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;
}
(二)第二类斯特林数

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

a.递推公式与性质

{ n m } = { n − 1 m − 1 } + { n − 1 m } ∗ 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 也可写作 n k = ∑ i = 0 m { k i } ∗ i ! ∗ ( n i ) 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时

n k n^k nk= n ( k − 1 ) ∗ n n^{(k-1)}*n n(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 = 0 i=0 i=0,i=k时 { k − 1 i } = 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时 { k i } = 0 {k\brace i}=0 {ik}=0

从组合意义理解 n k = ∑ i = 0 n { k i } ∗ i ! ∗ ( n i ) 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时

n k n^k nk= n ( k − 1 ) ∗ n n^{(k-1)}*n n(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行的第二类斯特林数

{ n m } = 1 m ! ∑ i = 0 m ( − 1 ) ( m − i ) ∗ ( m i ) ∗ m n {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) ( m i ) {m\choose i} (im)分别弄一个多项式然后FFT卷起来即可

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

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

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

​ 则 g ( m ) = ∑ i = 0 m h ( 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 = 0 m ( m i ) f ( i ) g(m)=\sum^m_{i=0} {m \choose i}f(i) g(m)=i=0m(im)f(i)

​ 则 f ( m ) = ∑ i = 0 m ( − 1 ) ( m − i ) ∗ ( m i ) ∗ 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)

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值