斯特林数

斯特林数

一、第二类斯特林数

1、定义:表示将 \(n\) 个两两不同的元素,划分为 \(k\) 个互不区分的非空子集的方案数。

2、递推式记为:\(S(n,m)=S(n-1,m-1)+mS(n-1,m)\),边界是:\(S(n,0)=[n=0]\)

3、组合数的意义:

  • 前一项表示将新的元素单独放入一个子集。

  • 后一项表示将新的元素放入一个已有的非空集合里面。

4、通项公式:

  • \(S(n,m)=\sum_{i=0}^{m}\frac{(-1)^{m-i}i^n}{i!(m-i)!}\)

\((1)\):第一种方案

  • 代码 \(n\) 能为 \(1e6\),时间复杂度:\(O(nlog(n))\),但是要保证质数和其他数互质。

  • 例题:牛客

template<typename T>
struct SN2{
    inline T qp(T a, T b, T p = 1e9 + 7) {
		T res = 1;
		a %= p;
		for (; b; b >>= 1LL, a = a * a % p) {
			if (b & 1) res = res * a % p;
		}
		return res;
	}
	
	inline T get_inv(T a, T p = 1e9 + 7) {
		return qp(a, p - 2, p);
	}
    
	int N;
	vector<T> fac, inv;
    SN2() {}
	SN2(int N_, T p = 1e9 + 7) : fac(N_ + 1), inv(N_ + 1) {
        N = N_;
        fac[0] = 1;
		for (T i = 1; i <= N; i++) fac[i] = fac[i - 1] * i % p;
		inv[N] = get_inv(fac[N], p);
		for (T i = N - 1; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % p;
    }
	
	inline T C(T n, T m, T p = 1e9 + 7) {
		if (n < m) {
			return (T)0;
		}
		return fac[n] * inv[n - m] % p * inv[m] % p;
	}
    
    inline T S2(T n, T m, T p = 1e9 + 7) {
        if (n < m) {
            return (T)0;
        }
        T res = 0;
        for (T i = 0; i <= m; i++) {
            if ((m - i) & 1) res = (res - (qp(i, n, p) * inv[i] % p * inv[m - i] % p) + p) % p;
            else res = (res + (qp(i, n, p) * inv[i] % p * inv[m - i] % p)) % p;
        }
        return res;
    }
};

\((2)\):第二种方案

  • 需要满足 \(n\)\((2e3-1e4)\) 之间,查询的时间复杂度为 \(O(1)\),不需要满足模数与其他数互质。
template<typename T>
struct SN2{
    inline T qp(T a, T b, T p = 1e9 + 7) {
		T res = 1;
		a %= p;
		for (; b; b >>= 1LL, a = a * a % p) {
			if (b & 1) res = res * a % p;
		}
		return res;
	}
	
	inline T get_inv(T a, T p = 1e9 + 7) {
		return qp(a, p - 2, p);
	}
    
	static const int N = 2000;
	T S2[N + 1][N + 1];
	SN2(T p = 1e9 + 7) {
        S2[0][0] = 1LL;
        for (T i = 1; i <= N; i++) {
            for (T j = 1; j <= i; j++) {
                S2[i][j] = (S2[i - 1][j - 1] + (j * S2[i - 1][j] % p)) % p;
            }
        }
    }
    
    T S(T n, T m) {
		return S2[n][m];
	}
};

5、同一行第二类斯特林数的计算:更新中

6、同一列第二类斯特林数的计算:更新中

二、第一类斯特林数

1、定义:也叫斯特林轮换数,表示将 \(n\) 个两两不同的元素,划分为 \(k\) 个互不区分的非空轮换的方案数。

2、注意:一个轮换指的是首尾相连的环形排列。我们可以写出一个轮换 \([A,B,C,D]\),并且我么认为 \([A,B,C,D]=[B,C,D,A]=[C,D,A,B]=[D,A,B,C]\),即,两个可以通过旋转二互相得到的转化是等价的,但是我们不认为两个可以通过翻转而得到的转换是等价的,即 \([A,B,C,D] \ne [D,C,B,A]\)

3、递推式为:\(S_{n}^{m}=S_{n-1}^{m-1}+(n-1)S_{n-1}^{m}\),边界是 \([S_{n}^{0}=[n=0]]\)

4、组合数意义:

  • 前一项表示将该元素放到一个单独的轮换里。

  • 后一项表示将该元素放入任何一个现有的轮换里。

5、通项公式:暂无。

6、\(n\)\((2e3-1e4)\) 之间,时间复杂度为 \(O(1)\)

template<typename T>
struct SN1{
    inline T qp(T a, T b, T p = 1e9 + 7) {
		T res = 1;
		a %= p;
		for (; b; b >>= 1LL, a = a * a % p) {
			if (b & 1) res = res * a % p;
		}
		return res;
	}
	
	inline T get_inv(T a, T p = 1e9 + 7) {
		return qp(a, p - 2, p);
	}
    
	static const int N = 2000;
	T S1[N + 1][N + 1];
	SN1(T p = 1e9 + 7) {
        S1[0][0] = 1;
        for (T i = 1; i <= N; i++) {
            for (T j = 1; j <= i; j++) {
                S1[i][j] = (S1[i - 1][j - 1] + ((i - 1) * S1[i - 1][j] % p)) % p;
            }
        }
    }
    
    T S(T n, T m) {
		return S1[n][m];
	}
};

7、同一行第一类斯特林数的计算:更新中

8、同一列第一类斯特林数的计算:更新中

posted @ 2024-09-08 10:57  grape_king  阅读(47)  评论(0)    收藏  举报