关于斯特林数

第一类斯特林数

意义:将n个不同的元素划分成m个环的方案数。

递推式:

(通常第一类斯特林数用小写 $s$ 表示,而第二类斯特林数用大写 $S$ 表示)

$$
s(n,m)=s(n-1,m-1)+s(n-1,m)\times (n-1)
$$

关于定义:

$P_{n}^{k} $ 表示从n个为物品中选出k个排列的方案数,显然有:
$$
C_{n}^{k}=\frac{P_{n}^{k}}{k!}
$$

$$
P_{n}^{k}=n\times (n-1)\times (n-2)\times......\times (n-k+1)
$$

考虑把式子展开,

对于第 $i$ 项(即 $n^{i}$ 项)的系数表示成有 $i$ 项选择 $n$ ,剩余的 $k-i$ 项选择 $k$ 个常数,所以对于第 $i$ 项系数是选择的 $i$ 个常数的乘积的和。

我们考虑把斯特林数左右反过来,因为每一行数的个数都差 $1$ ,这里的定义是向左看齐。
$$
s_{t}(n,m)=s_{t}(n-1,m-1)\times (n-1)+s_{t}(i-1,j)
$$
这样就这个递推式就可以理解为前 $i$ 个数我选了 $m$ 个数的乘积的和,因为可以选择的常数其实是从 $0$ ~ $k-1$ ,所以乘的系数是 $(n-1)$ 。

所以呢
$$
P_{n}^{k}=s(k,k)\times n^{k}-s(k,k-1)\times n^{k-1}...
$$

$$
P_{n}^{k}=\sum _{i=0}^{k}(-1)^{k-i}\times s(k,i)\times n^{i}
$$

所以第一类斯特林数是排列数公式的展开系数。

同时也得到第一类有符号斯特林数的多项式形式
$$
n(n-1)(n-2)...(n-k+1)=\sum_{i=0}^{k}(-1)^{k-i}S(k,i)n^{i}
$$
也可以推出第一类无符号斯特林数的多项式形式
$$
n(n+1)(n+2)...(n+k-1)=\sum_{i=0}^{k}S(k,i)n^{i}
$$
当前得到的式子,左边用分治 $NTT$ 求出第 $i$ 项系数即为 $S(k,i)$ ,这个求法效率是 $O(nlog^{2}n)$

接下来 $O(nlogn)$ 的倍增做法,

考虑当我们已经知道 $S_{n}$ 的生成函数为
$$
\prod_{i=0}^{n-1}(x+i)=\sum f_{i}x^{i}
$$
以此来研究 $S_{2n}$ 的生成函数
$$
\prod_{i=n}^{2n-1}(x+i)\\
=\prod_{i=0}^{n-1}(x+i+n)\\
=\sum_{i=0}^{n}f_{i}(x+n)^{i}
$$
再用二项式定理展开:
$$
=\sum_{i=0}^{n}f_{i}\sum C_{i}^{j}x^{j}n^{i-j}\\
=\sum_{j=0}^{n}\sum_{i=j}^{n}f_{i}\frac{i!}{j!(i-j)!}x^{j}n^{i}n^{-j}\\
=\sum_{j=0}^{n}\frac{1}{j!n^{j}}(\sum_{i-j}^{n}\frac{i!}{(i-j)!}n^{i})x^{j}
$$
那么对于括号内的多项式 $NTT$ $O(nlogn)$ 得到,对于奇数的情况先求出 $2n$ 的答案,再单独乘最后一项。

以下代码:

#include<bits/stdc++.h>
#define il inline
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=3e5+5,p=998244353;
int t1[N],t2[N],t3[N],t4[N];
int n,a,b,jc[N],ny[N],t=1,l,f[N],v[N],g[2][40];
il int read(){
    int x,f=1;char ch;
    _(!)ch=='-'?f=-1:f;x=ch^48;
    _()x=(x<<1)+(x<<3)+(ch^48);
    return f*x;
}
il int ksm(LL a,int y){
    LL b=1;
    while(y){
        if(y&1)b=b*a%p;
        a=a*a%p;y>>=1;
    }
    return b;
}
il int mu(int x,int y){
    return (x+y>=p)?x+y-p:x+y;
}
il int C(int n,int m){
    return 1ll*jc[n]*ny[m]%p*ny[n-m]%p;
}
il void init(int n){
    t=1;l=0;
    while(t<=n)t<<=1,l++;
    for(int i=0;i<t;i++)v[i]=(v[i>>1]>>1)|((i&1)<<l-1);
}
il void dft(int *x,int op){
    for(int i=0;i<t;i++)if(i<v[i])swap(x[i],x[v[i]]);
    for(int i=1,z=1;i<t;i<<=1,z++){
        int wn=g[op][z];
        for(int j=0;j<t;j+=i<<1){
            for(int w=1,A,B,k=0;k<i;k++,w=1ll*w*wn%p){
                A=x[j+k],B=1ll*x[i+j+k]*w%p;
                x[j+k]=mu(A,B);x[i+j+k]=mu(A,p-B);
            }
        }
    }
    int kk=ksm(t,p-2);
    if(op)for(int i=0;i<t;i++)x[i]=1ll*x[i]*kk%p;
}
il void solve(int *x,int n){
    if(n==1){
        x[0]=0;x[1]=1;
        return;
    }
    if(n&1){
        solve(x,n-1);x[n]=0;
        for(int i=n-1;i>=0;i--)x[i+1]=mu(1ll*(n-1)*x[i+1]%p,x[i]);
        return;
    }
    solve(x,n>>1);
    init(n);
    for(int i=(n>>1)+1;i<=n;i++)
        t1[i]=t2[i]=t3[i]=t4[i]=0;
    for(int i=0;i<=(n>>1);i++){
        t1[i]=1ll*x[i]*ksm(n>>1,i)%p*jc[i]%p;
        t2[i]=ny[i];
    }
    reverse(t1,t1+(n>>1)+1);
    dft(t1,0);dft(t2,0);
    for(int i=0;i<t;i++)t3[i]=1ll*t1[i]*t2[i]%p;
    dft(t3,1);reverse(t3,t3+(n>>1)+1);
    for(int i=0;i<=(n>>1);i++)t4[i]=1ll*t3[i]*ksm(ksm(n>>1,i),p-2)%p*ny[i]%p;
    dft(t4,0);dft(x,0);
    for(int i=0;i<t;i++)x[i]=1ll*x[i]*t4[i]%p;
    dft(x,1);
}
int main()
{
    n=read();a=read();b=read();
    if(n==1&&a==1&&b==1)return puts("1"),0;
    if(a+b-1>n||a<1||b<1)return puts("0"),0;
    g[0][0]=3;g[1][0]=ksm(3,p-2);
    while(t<=n)t<<=1,l++;
    for(int i=1,z=1;i<t;i<<=1,z++){
        g[0][z]=ksm(g[0][0],(p-1)/(i<<1));
        g[1][z]=ksm(g[1][0],(p-1)/(i<<1));
    }
    jc[0]=1;for(int i=1;i<=t;i++)jc[i]=1ll*i*jc[i-1]%p;
    ny[t]=ksm(jc[t],p-2);for(int i=t;i;i--)ny[i-1]=1ll*i*ny[i]%p;
    solve(f,n-1);
    printf("%d\n",1ll*f[a+b-2]*C(a+b-2,a-1)%p);
    return 0;
}
View Code

 

一些关于第一类斯特林数的性质:

1. $s(0,0)=1​$

2. $s(n,0)=0 (n>0)$
3. $s(n,1)=(n-1)!$
4. $s(n,n-1)=C_{n}^{2}​$
5. $s(n,2)=(n-1)!\times \sum_{i=1}^{n-1} \frac{i}{1}$
6. $s(n,n-2)=2\times C_{n}^{3}+3\times C_{n}^{4}$
7. $\sum_{k=0}^{n}s(n,k)=n!​$

第二类斯特林数

意义:将 $n$ 个不同的元素拆成 $m$ 个集合的方案数(不存在空集)。

(与第一类不同于,第二类球在集合中无序的)

递推式:

$$
S(n,m)=S(n-1,m-1)+m\times S(n-1,m)
$$
容斥式子:

枚举空盒子的个数,求出至少有 $i$ 个空盒的方案数容斥得到恰好有 $m$ 个盒子的方案数。
$$
S(n,m)=\frac{1}{m!}\sum_{k=0}^{m}(-1)^{k}\times C_{m}^{k}\times (m-k)^{n}
$$
$ps:$ 因为集合是相同的,所以最后要 $\times \frac{1}{m!}$

观察到式子是卷积的形式,所以可以 $NTT$ 在 $O(nlogn)$ 内求出 $S(n,0),S(n,1)......$

性质:
$$
n^{k}=\sum_{i=0}^{k}S(k,i)\times i!\times C_{n}^{i}
$$
左边相当于把 $k$ 个球随便放在 $i$ 个不同的盒子里

右边表示枚举 $k$ 个球装在 $i$ 个盒子里,(因为左边盒子是不同的,为了一致 $\times i!$ 表示不同的盒子),再组合数 $C_{n}^{k}$ 选出 $k$ 个非空盒子。

继续变化
$$
n^{k}=\sum_{i=0}^{k}S(k,i)n^{\underline{k}}
$$
$n^{\underline{k}}$ 表示 $n$ 的 $k$ 次下降幂,等于 $n\times (n-1)\times (n-2)\times ......\times (n-k+1)​$

斯特林反演后续填坑...

posted @ 2019-03-09 10:36  Jessiejzy  阅读(399)  评论(0编辑  收藏  举报