5251 斯特林数

5251 斯特林数_第1张图片

由定义得递推式
S2 (i , j) = S2 (i−1 , j−1) + S2 (i−1 , j) ∗ j
这个式子用于 O( n^2 ) 计算 (n , n) 以内的所有斯特林数

若要求某一个 S2(n , m) ,可推导通项公式
首先无视无空盒条件,放法有 m^n 种
然后枚举有 k 个空盒,可得出多算的有
C(k , m) ∗ (m−k)^n
这要套个容斥,因为 (m−k)^n 并不保证这 m-k 个盒子中全是有的。

换句话说,设不保证无空盒的放法全集是 S ,
Ai 表示S中第 i 个盒子为空的放法子集.
减去C(1 , m) ∗ (m−1)^n 即为 减去 ∑Ai
显然我们多减去了Ai∩Aj 这一类放法. 即有 i , j 同时为空的放法
因此要加回 Ai∩Aj ,但又多加了 Ai∩Aj∩Ak ,
以此类推,理解一下.

#include 
#include 
#define ll long long
using namespace std;
const int _MOD = 1000000007;
int n, m;
ll pow[1000010];
ll nipow[1000010];
inline ll Pow(ll a, ll b) {
    ll res = 1;
    while (b) {
        if (b&1) res = res*a%_MOD;
        a = a*a%_MOD;
        b>>=1;
    }
    return res;
}
inline ll _(int a) {
    return a&1?_MOD-1:1;
}
int main() {
    scanf("%d%d", &n, &m);
    pow[0] = 1;
    for (int i = 1; i <= m; i++) {
        pow[i] = pow[i-1]*i%_MOD;
    }
    nipow[m] = Pow(pow[m], _MOD-2);
    for (int i = m-1; i > -1; i--) {
        nipow[i] = nipow[i+1]*(i+1)%_MOD;
    }
    ll res = 0;
    for (int i = 0; i <= m; i++) {
        res+=_(m-i)*Pow(i, n)%_MOD*nipow[i]%_MOD*nipow[m-i]%_MOD;
        if (res>=_MOD) res-=_MOD;
    }
    printf("%lld", res);
    return 0;
}

你可能感兴趣的:(c++)