斯特林数
(一)第一类斯特林数
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]=[m−1n−1]+[mn−1]∗(n−1)
新来的元素既可以自己成为一个圆排列,又可以放在任意一个已有元素的后面。
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)k−i∗ni
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 =(n−k+1)∗∑i=0k−1[ik−1]∗(−1)k−1−i∗ni
= 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 =n∗∑i=0k−1[ik−1]∗(−1)k−1−i∗ni−(k−1)∗∑i=0k−1[ik−1]∗(−1)k−1−i∗ni
= 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 =n∗∑i=1k[i−1k−1]∗(−1)k−i∗ni−1−(k−1)∗∑i=0k−1[ik−1]∗(−1)k−1−i∗ni
= ∑ 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[i−1k−1]∗(−1)k−i∗ni−∑i=1k(k−1)∗[ik−1]∗(−1)k−1−i∗ni //注意i=0时若k=1则 k − 1 = 0 k-1=0 k−1=0,否则 [ k − 1 i ] = 0 {k-1\brack i}=0 [ik−1]=0;i=k时 [ k − 1 i ] = 0 {k-1\brack i}=0 [ik−1]=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[i−1k−1]∗(−1)k−i∗ni+∑i=1k(k−1)∗[ik−1]∗(−1)k−i∗ni
= ∑ 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([i−1k−1]+(k−1)∗[ik−1])∗(−1)k−i∗ni
= ∑ 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)k−i∗ni
证明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+k−1)∗∑i=0k−1[ik−1]∗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∗[i−1k−1]∗ni+∑i=1k[ik−1]∗(k−1)∗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=0n−1x+i得到 ∏ i = 0 n − 1 x + n + i \prod^{n-1}_{i=0}x+n+i ∏i=0n−1x+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=0L−1ai∗xi,则多项式 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=0L−1ai∗(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=0L−1ai∗(x+n)i=∑i=0L−1ai∗∑j=0i(ji)∗ni−j∗xj //二项式展开
= ∑ 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=0L−1(∑j=iL−1(ij)∗nj−i∗aj)∗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=iL−1(ij)∗nj−i∗aj
= 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!1∑j=iL−1(j−i)!j!∗nj−i∗aj
令 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!nj且当j≤0时=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!1∑j=0L−1g(j)∗h(j−i)
事实上这已经是一个经典问题了,但是我忘了,所以再推一遍:
不希望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!1∑j=0L−1g(j)∗h(j−i+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!1∑j=0L−1g(j)∗h(i−j+L−1)
就这样卷积完以后,再左移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}={m−1n−1}+{mn−1}∗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(k−1)∗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 {ik−1}=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(k−1)∗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!1∑i=0m(−1)(m−i)∗(im)∗mn n是常数, ( − 1 ) ( m − i ) (-1)^{(m-i)} (−1)(m−i)和 ( 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)(m−i)∗(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)(m−i)∗{im}∗mn