贝尔数求集合划分方案总数

问题描述

因为长期钻研算法, 无暇顾及个人问题,BUAA ACM/ICPC 训练小组的帅哥们大部分都是单身。

某天,他们在机房商量一个绝妙的计划"一卡通大冒险"。

这个计划是由 wf 最先提出来的,计划的内容是,把自己的联系方式写在校园一卡通的背面,然后故意将自己的卡"遗失"在某处(如水房,TD,食堂,主 M。。。。)他们希望能有 MM 看到他们遗失卡,能主动跟他们联系,这样就有机会请 MM 吃饭了。

他们决定将自己的一卡通夹在基本相同的书里,然后再将书遗失到校园的各个角落。正当大家为这个绝妙的计划叫好时,大家想到一个问题。

很明显,如果只有一张一卡通,那么只有一种方法,即,将其夹入一本书中。当有两张一卡通时,就有了两种选择,即,将两张一卡通夹在一本书里,或者分开夹在不同的书里。

当有三张一卡通时,他们就有了 5 种选择,即:{``{A},{B},{C}},{``{A,B},{C}},{``{B,C},{A}},{``{A,C},{B}},{``{A,B,C}},于是,这个邪恶计划的组织者 wf 希望了解,如果 ACM 训练对里有 n 位帅哥(即有 N 张一卡通),那么要把这些一卡通夹到书里有多少种不同的方法。

输入格式

包含多组数据,第一行为 n(1<=n<=5×10^5),表示接下来有 n 组数据,以下每行一个数 x(1<=x<=2000),表示共有 x 张一卡通。

输出格式

对每组数据,输出一行,不同的方法数,因为这个数可能非常大,我们只需要它除以 1000 的余数。

输入样例

复制代码
4
1
2
3
100

输出样例

复制代码
1
2
5
751

前置知识

第二类斯特林数

第二类斯特林数(斯特林子集数),也可记做 𝑆(𝑛,𝑘),表示将 𝑛 个两两不同的元素,划分为 𝑘 个互不区分的非空子集的方案数。

递推式为:;通项公式为:

贝尔数

有限集划分数又称贝尔数,是组合数学中表示基数为n的集合所有划分方式数量的整数数列,记为。它用于求将n个元素划分为若干互不相交非空子集的不同方法总数(即求n个元素总共有多少种划分方式,每种划分方式满足划分定义)是因为空集正好有1种划分方法。

eg:对 {1,2,3},所有划分方案是:

  1. { {1,2,3} }
  2. { {1}, {2,3} }
  3. { {2}, {1,3} }
  4. { {3}, {1,2} }
  5. { {1}, {2}, {3} }

一共 5 种划分方案。因此

这里说到划分就想到离散数学中的划分与覆盖的相关概念:

A:一个集合**;** ,S是由 A 的各个子集构成的集合(叫子集族)

覆盖:

  1. (即子集不能为空集);
  2. (即所有子集并起来要等于全集A)。

划分:

  1. (即子集不能为空集);
  2. (即所有子集并起来要等于全集A);
  3. (即任意两个子集不相交)。

第三点还说明了:在划分中,集合A中的每个元素只能被选择一次。而覆盖没有这个要求,因此,覆盖可以选择同一个元素在不同子集中多次出现。但它们最终都需要满足所有子集并起来能覆盖全集。

无论是覆盖还是划分只要求每个子集不能是空集,并没有要求划分必须至少有一个子集。(是可行的,因为它表示划分的是一个空集;但是则是不可行的,因为它表示的是划分的子集是一个空集。这也是的原因。)

递推公式:。每个贝尔数都是相应的第二类斯特林数的和,因为第二类斯特林数是把基数为 𝑛 的集合划分为正好 𝑘 个非空集的方法数目,因此,贝尔数可以表示为:

贝尔三角形

该三角形的每行的首项是贝尔数,可以利用这个三角形来递推求出贝尔数。

构造方法:

  • 对于 𝑛>=1,第 𝑛 行首项等于上一行的末项,即
  • 对于 𝑚,𝑛>=1,第 𝑛 行第 𝑚 项等于它左边和左上角两个数之和,即

这里给出的递推公式以及通项公式等均不给出证明,如果有感兴趣的可以自行网上查阅。

上述内容引用自:oi-wiki网站

代码实现

java 复制代码
//题目要求结果对1000取模(如果不取模,对于long类型,也可能出现溢出)
import java.util.Scanner;

public class Main{
    public static void main(String[] args) {
        //贝尔三角:用来求贝尔数,第 i 行第 0 列 = 贝尔数 B_i
        long[][] bellTriangle=new long[2001][2001];
        //a_{0,0} = 1
        bellTriangle[0][0]=1;
        for (int n = 1; n < 2001; n++) {
            //第 𝑛 行首项等于上一行的末项,即 a_{n,0}=a_{n-1,n-1}
            bellTriangle[n][0]=bellTriangle[n-1][n-1]%1000;
            for (int m = 1; m <= n; m++) {
                //第 𝑛 行第 𝑚 项等于它左边和左上角两个数之和,即a_{n,m}=a_{n,m-1}+a_{n-1,m-1}
                bellTriangle[n][m]=(bellTriangle[n][m-1]+bellTriangle[n-1][m-1])%1000;
            }
        }

        Scanner sc = new Scanner(System.in);
        int t=sc.nextInt();
        for (int i = 0; i < t; i++) {
            System.out.println(bellTriangle[sc.nextInt()][0]);
        }
    }
}
相关推荐
三品吉他手会点灯4 小时前
C语言学习笔记 - 20.C编程预备计算机专业知识 - 变量为什么必须的初始化【重点】
c语言·笔记·学习
kobesdu4 小时前
【ROS2实战笔记-12】rosshow:终端里的盲文可视化与无头机器人的现场调试
笔记·机器人·ros·移动机器人
代码AI弗森4 小时前
一文理清楚“算力申请 / 成本测算 / 并发评估”
java·服务器·数据库
sakiko_5 小时前
UIKit学习笔记1-创建项目(使用UIKit)、使用组件
笔记·学习
Old Uncle Tom5 小时前
OpenClaw 记忆系统 -- 记忆预加载
java·数据结构·算法·agent
小小小米粒5 小时前
Collection单列集合、Map(Key - Value)双列集合,多继承实现。
java·开发语言·windows
智者知已应修善业5 小时前
【51单片机中的打飞机设计】2023-8-25
c++·经验分享·笔记·算法·51单片机
摇滚侠5 小时前
expdp 查看帮助
java·数据库·oracle
:1216 小时前
java基础
java·开发语言
曹牧7 小时前
Spring:@RequestMapping注解,匹配的顺序与上下文无关
java·后端·spring