贝尔数

怎么感觉这么简单的东西被我写得这么搞基

前置知识:

  • 第二类斯特林数(Stirling Number)\(\begin{Bmatrix}n\\k\end{Bmatrix}\)\(S(n,k)\) 表示将 \(n\) 个元素划分为 \(k\) 个互不区分的非空子集的方案数。
    • 递推式:\(S(n,k) = S(n-1,k-1) + k \times S(n-1,k)\),其中 \(S(n,0)=[n=0]\)

贝尔数 \(B_n\) 表示 \(n\) 个元素被划分为若干个互不区分的非空子集的方案数(注意 \(B_0 = 1\))。

显然 \(B_n = \sum\limits_{k=0}^{n}{S(n,k)}\) 就是求同一行第二类斯特林数的和,luogu - P5395 第二类斯特林数·行

还有递推式 \(B_{n+1} = \sum\limits_{k=0}^{n}{\dbinom{n}{k}B_k}\)(考虑 \(a_{n+1}\) 和哪些元素一个集合)

打表代码
#include <bits/stdc++.h>

using namespace std;
using LL = __int128_t;

const LL mod = LL(1e18) + 3;

void write(LL x){ if(x > 9) write(x / 10); putchar(x % 10 + '0'); }

LL qpow(LL A, LL B){
  LL ret = 1;
  while(B > 0){
    if(B & 1) ret = ret * A % mod;
    A = A * A % mod, B >>= 1;
  }
  return ret;
}

LL fac[1003], ifac[1003], B[1003];
LL C(int A, int B){ return fac[B] * ifac[A] % mod * ifac[B - A] % mod; }

int main(){
  ios::sync_with_stdio(0), cin.tie(0);
  fac[0] = ifac[0] = 1;
  for(int i = 1; i <= 1000; i++) fac[i] = fac[i - 1] * i % mod, ifac[i] = qpow(fac[i], mod - 2);
  B[0] = 1;
  for(int n = 1; n <= 15; n++){
    B[n] = 0;
    for(int k = 0; k <= n - 1; k++) B[n] = (B[n] + C(k, n - 1) * B[k]) % mod;
    write(n), putchar(' '), write(B[n]), putchar('\n');
  }
  return 0;
}

表:

1:  1
2:  2
3:  5
4:  15
5:  52
6:  203
7:  877
8:  4,140
9:  21,147
10: 115,975
11: 678,570
12: 4,213,597
13: 27,644,437
14: 190,899,322
15: 1,382,958,545

这玩意就用来分析时间复杂度的,在 代码源 2025 CSP-S 模拟赛 Day13 - D题 蝴蝶图 & QOJ - #913. 蝴蝶图 中用到了(\(B_{11} = 678,570\))。

如何枚举划分为若干个互不区分的非空子集的方案

前置知识:子集遍历

函数 dfs(int s) 表示 \(s\) 还没被选。考虑给每个集合内的点,标记为集合中最小的位置。

#include <bits/stdc++.h>

using namespace std;
using LL = long long;

int n, rt[20], cnt = 0;

void dfs(int s){
  if(!s){
    cnt++;
    for(int i = 1; i <= n; i++){
      cout << rt[i] << " ";
    }
    cout << "\n";
    return;
  }
  int lowbit = (s & (-s)), p = 0;
  while((1 << p) != lowbit) p++;
  p++, rt[p] = p;
  s ^= lowbit;
  int st = s;
  while(st){
    for(int i = 1; i <= n; i++) if((st >> (i-1)) & 1) rt[i] = p;
    dfs(s ^ st);
    st = (st - 1) & s; 
  }
  dfs(s);
}

int main(){
  ios::sync_with_stdio(0), cin.tie(0);
  n = 5, dfs((1 << 5) - 1);
  cout << cnt << "\n";
  return 0;
}
posted @ 2025-10-02 16:53  hhhqx  阅读(17)  评论(0)    收藏  举报