【学习笔记】薛定谔的喵咪Cat—球盒问题(全详解)
【题目描述】
当一个猫在盒子里时,因为放射物的状态我们不知道,所以猫的状态我们也不知道,这就所谓猫的生死纠缠态,也是所谓的薛定谔的猫。
当我们做需要大量实验时,就需要统计猫的个数与盒子的数量,以及之间的关系。因为实验情况不同,所以我们要研究的模型也不尽相同。我们用 (opt) 表示。
(opt = 1:) 猫的颜色不同,盒子的颜色不同,允许盒子为空。
(opt = 2:) 猫的颜色相同,盒子的颜色不同,不许盒子为空。
(opt = 3:) 猫的颜色相同,盒子的颜色不同,允许盒子为空。
(opt = 4:) 猫的颜色不同,盒子的颜色相同,不许盒子为空。
(opt = 5:) 猫的颜色不同,盒子的颜色不同,不许盒子为空。
(opt = 6:) 猫的颜色不同,盒子的颜色相同,允许盒子为空。
(opt = 7:) 猫的颜色相同,盒子的颜色相同,允许盒子为空。
(opt = 8:) 猫的颜色相同,盒子的颜色相同,不许盒子为空。
(opt = 9:) 此时猫分两种颜色,黑色和白色分别各有 (a) 只,盒子数量和猫的个数相同,每个盒子里面只能放一只猫,并且必须满足如下限制,即每一个白色猫必须和一只黑色猫配对(白猫在黑猫前,允许嵌套)。
(eg.) 我们用 (0) 表示白猫,(1) 表示黑猫,则:
(0011),(010101),(001011) 合法。
(1100),(101010),(010110) 不合法。
注:某物有色代表此物每一个都不相同
给定 (opt),猫的数量 (a),盒子的数量 (b),将猫放入盒子,求所有本质不同的合法方案数。
【输入】
第一行包含一个整数 (q) 表示询问的个数,接下来 (q) 行,每行包含三个整数 (opt,a,b),分别表示当前询问的是模型 (opt),其中猫为 (a) 个,盒子为 (b) 个。
【输出】
输出包含 (q) 行,每行一个整数表示询问的答案,要求答案对 (998244353) 取模。
【样例】
样例输入:
9
1 3 2
2 3 2
3 3 2
4 3 2
5 3 2
6 3 2
7 3 2
8 3 2
9 3 6
样例输出:
8
2
4
3
6
4
2
1
5
【数据范围】
测试点 | (q) | (a,b) | 包含 (opt) |
---|---|---|---|
(1) | (q leqslant 5) | (a,b leqslant 5) | (1) |
(2) | (q leqslant 10) | (a,b leqslant 10) | (1,2) |
(3) | (q leqslant 15) | (a,b leqslant 10^6) | (1,2,3) |
(4) | (q leqslant 20) | (a,b leqslant 100) | (1,2,3,4) |
(5) | (q leqslant 25) | (a,b leqslant 100) | (1,2,3,4,5) |
(6) | (q leqslant 30) | (a,b leqslant 100) | (1,2,3,4,5,6) |
(7) | (q leqslant 35) | (a,b leqslant 100) | (7,8) |
(8) | (q leqslant 40) | (a,b leqslant 10^6) | (9) |
(9) | (q leqslant 45) | (a,b leqslant 100) | (7,8,9) |
(10) | (q leqslant 50) | (a,b leqslant 100) | (1,2,3,4,5,6,7,8,9) |
【分析】
(a) 只喵咪放入 (b) 个盒子,其实就是总共 (8) 种球盒模型混进去了一个不明物体QAQ。
模型 | 球是否有色 | 盒是否有色 | 盒可否为空 | 计算公式 | 注 |
---|---|---|---|---|---|
(1) | √ | √ | √ | (b^a) | 快速幂 |
(2) | × | √ | × | (C_{a-1}^{b-1}) | 组合数 |
(3) | × | √ | √ | (C_{a+b-1}^{b-1}) | 组合数(或(C_{a+b-1}^a)) |
(4) | √ | × | × | (S_2(a,b)) | 第二类斯特林数 |
(5) | √ | √ | × | (b!*S_2(a,b)) | 第二类斯特林数 |
(6) | √ | × | √ | (B_a) | 贝尔数(或(sum_{i=1}^bS_2(a,i))) |
(7) | × | × | √ | (dp[a+b][b]) | (dp[i][j]=dp[i-j][j]+dp[i-1][j-1]) |
(8) | × | × | × | (dp[a][b]) | (dp[i][j]=dp[i-j][j]+dp[i-1][j-1]) |
接下来将会以 (“) 喵咪 (”) 指代 (“) 球 (”) 作解释。
1:快速幂
问题描述: 球有色,盒子有色,盒子可为空。((a,b leqslant 10^6))
这个应该是最简单的了。对于每一个喵咪都可以任意的安排在任意一个盒子里面,于是每只喵咪都有 (b) 种选择,一共 (a) 只喵咪。
得出答案为:(b^a) 。
2:组合数
问题描述: 球无色,盒子有色,盒子不可为空。((a,b leqslant 10^6))
既然喵咪都长一个样,那就把它们排成一排站好,在其之间插入 (b-1) 个挡板,将其分为 (b) 个部分,每个部分都有若干只喵咪,而(a) 只喵咪之间一共有 (a-1) 个空隙可插。
得出答案为: (C_{a-1}^{b-1}) 。
3:组合数
问题描述: 球无色,盒子有色,盒子可为空。((a,b leqslant 10^6))
在上述模型 (2) 的基础上稍作改进即可。
盒子不可为空,这说明了什么?(a) 只喵咪之间的一共 (a+1) 个空位置里面(对于这道题,喵咪队列的外面也可以插了),每个位置都可插无限个挡板(实际上最大值为 (b-1) 个),也就是说板子插到哪儿,同时插几根板子,都没有限制。
既然没有那么多要求,那就干脆把喵咪和板子都看作同一类元素,插进去后的状态就是这一共 (a+b-1) 个元素的某种排列,要求是这个排列中板子的个数为 (b-1)(或者说喵咪的个数为 (a))。
得出答案为:(C_{a+b-1}^{b-1})(或(C_{a+b-1}^a)) 。
4:第二类斯特林数
问题描述: 球有色,盒子无色,盒子不可为空。((a,b leqslant 100))
这里的喵咪有颜色分别,也就是说每只喵咪都不相同,而盒子又都是没有区别的,那么就可以考虑将其视作集合。将盒子视为集合,喵咪视为里面的元素,恰好满足集合的定义。再看看 (Stirling) 数的定义:(S_2(a,b)) 表示将 (a)个不同的元素拆分成 (b) 个集合的方案数。于是这个问题就这样解决啦!
得出答案为:(S_2(a,b)) 。
5:第二类斯特林数
问题描述: 球有色,盒子有色,盒子不可为空。((a,b leqslant 100))
盒子与球 ([P1287])总算是找到一道例题了。。。。
在上述模型 (4) 的基础上稍作改进即可。
由于集合出现了颜色分别,因此对于每一种元素(喵咪们)的划分,都可以有 (b!) 种方案提供集合来装下这些元素。
得出答案为:(b!*S_2(a,b)) 。
6:贝尔数
问题描述: 球有色,盒子无色,盒子可为空。((a,b leqslant 100))
在上述模型 (4) 的基础上稍作改进即可。
盒子可以为空,说明划分出来的集合数目可以是任意的(当然要小于等于 (b) 啦QAQ),为什么呢?假如我们划分出了 (5) 个集合来装元素,那么剩下的 (b-5) 个作为空集就可以了。由于本题数据不大((a,b leqslant 100)),直接暴力枚举划分 (1)~(b) 个集合的方案数再求和就 (ok) 啦。
实际上就是贝尔数。
得出答案为:(B_a=sum_{i=1}^bS_2(a,i))
7 , 8:递推
关于 (7) 和 (8) 似乎有一个极其复杂数学公式推导,奈何本人能力有限,无法理解,只会递推方程解决。
先说 (8),再说 (7)。
模型8
问题描述: 球无色,盒子无色,盒子不可为空。((a,b leqslant 100))
设 (dp[i][j]) 表示 (i) 只喵咪和 (j) 个盒子的方案数。
问题可理解为:求关于 (x_{1,2,3...b}) 的方程 (sum_{i=1}^b x_i=a) (()为了避免方案重复:(1 leqslant x_1 leqslant x_2 ... leqslant x_b)) 的解的个数。
这里可以分两种情况:
((1).) (x_1=1) ,
原方程可化为:(sum_{i=2}^b x_i=a-1) ((1 leqslant x_2 leqslant x_3 ... leqslant x_b)),
即:(sum_{i=1}^{b-1} x'_i=a-1) ((1 leqslant x'_1 leqslant x'_2 ... leqslant x'_{b-1})),
其方案数为 (dp[a-1][b-1]) 。
((2).) (x_1 geqslant 2) ,
原方程可化为:(sum_{i=1}^b (x_i-1)=a-b) ((2 leqslant x_1 leqslant x_2 ... leqslant x_b)),
即 (sum_{i=1}^b x'_i=a-b) ((1 leqslant x'_1 leqslant x'_2 ... leqslant x'_b)),
其方案数为 (dp[a-b][b])。
综上所述,递推方程为:(dp[a][b]=dp[a-1][b-1]+dp[a-b][b]) 。
得出答案为: (dp[a][b])。
模型7
问题描述: 球无色,盒子无色,盒子可为空。((a,b leqslant 100))
在上述模型 (8) 的基础上稍作改进即可。
盒子可以为空就意味着多了一种情况:(x_?=0),可以在方程两边同时加上一个 (b),原方程可化为:(sum_{i=1}^b (x_i+1)=a+b) ((0 leqslant x_1 leqslant x_2 ... leqslant x_b)),
问题可转化为:求关于 (x'_{1,2,3...b}) 的方程 (sum_{i=1}^b x'_i=a+b) ((1 leqslant x'_1 leqslant x'_2 ... leqslant x'_b))的解的个数。和模型 (8) 里那个问题一样,只是这里的答案要变一下 。
得出答案为:(dp[a+b][b])。
9:Catalan数
(部分摘自百度百科以及(Silent)_(EAG))
问题描述: 此时猫分两种颜色,黑色和白色分别各有 (a) 只,盒子数量和猫的个数相同,每个盒子里面只能放一只猫,并且必须满足如下限制,即每一个白色猫必须和一只黑色猫配对(白猫在黑猫前,允许嵌套)。((a,b leqslant 10^6))
(eg.) 我们用 (0) 表示白猫,(1) 表示黑猫,则:
(0011),(010101),(001011) 合法。
(1100),(101010),(010110) 不合法。
实际上这已经不能算是球盒模型的问题了,只是 (Catalan) 的一种变型而已。
当时这道题作为一道 (noip) 考前模拟的压轴题,是一个学长自己出的,后来他告诉我们:正规考式的压轴题一般都是这种按子问题得分的形式,而且为了防 (AK) 会把最后一问设置地极其反人类,当时我就懵逼了。。。现在想想好像难度也不是太高,只要对 (Catalan) 熟悉,看一眼就知道是简单套路,或者直接打个表也能看出来 (() (Catalan) 数的前几项: (1,1,2,4,14,42,132))。
关于这个问题的 (6) 种变型
(1). 火车进出栈
一个栈的进栈序列为 (1,2,3,..n,) 有多少个不同的出栈序列?
(2). 找零钱(找一半)
有 (2n) 个人排成一行进入剧场。入场费 (5) 元。其中只有 (n) 个人有一张 (5) 元钞票,另外 (n) 人只有 (10) 元钞票,剧院无其它钞票,问有多少中方法使得只要有 (10) 元的人买票,售票处就有 (5) 元的钞票找零?
(3). 三角网格
形如这样的直角三角形网格,从左上角开始,只能向右走和向下走,问总共有多少种走法?
(4). 括号排列
有 (n) 对括号,可以并列或嵌套排列,共有多少种情况?
(5). 球盒问题
见上。
(6). 最适合理解的模型
(n) 个 (0) 和 (n) 个 (1) 组成一个 (2n) 位的 (2) 进制数,要求从左到右扫描时,(1) 的累计数始终都小于等于 (0) 的累计数,求满足条件的数有多少?
理解方式
模型 | ||
---|---|---|
((1)) | 入栈 | 出栈 |
((2)) | 用 (5) 元支付 | 用 (10) 元支付 |
((3)) | 向下走 | 向右走 |
((4)) | 左括号 | 右括号 |
((5)) | (0) | (1) |
((6)) | (0) | (1) |
注:同列事件可视为等价,且在题目要求中左边事件的次数/大小需要始终大于右边。
观察模型 ((6)):在 (2n) 位上填入 (n) 个 (0) 的方案数为 (C_{2n}^n)。而从 (C_{2n}^n) 中减去不符合要求的方案数即为所求答案。
在从左往右扫时,必然会在某一个奇数位 (2p+1) 上首先出现 (p+1) 个 (1),和 (p) 个 (0)
此后的 ([2p+2,2n]) 上的 (2n−(2p+1)) 位有 (n−p) 个 (0) , (n−p−1) 个 (1)。如若把后面这部分 (2n−(2p+1)) 位的 (1) 与 (0) 互换,使之成为 (n−p) 个 (1),(n−p−1) 个 (0),结果得 (1) 个由 (n+1) 个 (1) 和 (n−1) 个 (0) 组成的 (2n) 位数,即一个不合法的方案必定对应着一个由 (n+1) 个 (1) 和 (n-1) 个 (0) 组成的一个排列。
还可以倒过来反证:
任意一个由 (n+1) 个 (1) 和 (n-1) 个 (0) 组成的一个排列,由于 (1) 的个数多了 (2) 个,且 (2n) 为偶数,所以必定在某个奇数位 (2p+1) 上出现 (1) 的个数超过 (0) 的个数。同样把后面部分 (1) 和 (0) 互换,成为了由 (n) 个 (0) 和 (n) 个 (1) 组成的 (2n) 位数。
由此,每一个不合法的方案总是与唯一一个由 (n+1) 个 (1) 和 (n−1) 个 (0) 组成的排列一一对应。
于是,不合法的方案数就可以写作:(C_{2n}^{n+1}),得出答案为: (Catalan(n)=C_{2n}^n-C_{2n}^{n+1})。
可以将这个式子再化简一下:
(egin{aligned} ext Catalan(n) &=C_{2 n}^{n}-C_{2 n}^{n+1} \ &=frac{(2 n) !}{n ! n !}-frac{(2 n)}{(n+1) !(n-1) !} \ &=frac{(2 n) !}{frac{n+1}{n+1} * n(n-1) !}-frac{(2 n) !}{(n+1) !(n-1) !} \ &=frac{(2 n) !}{(n+1) ! *(n-1) !} *left(frac{n+1}{n}-1 ight) \ &=frac{(2 n) !}{(n+1) n ! *(n-1) !} * frac{1}{n} \ &=frac{(2 n) !}{(n+1) n ! * frac{n !}{n+1}} \ &=frac{C_{2 n}^{n}}{n+1} end{aligned})
【Code】
#include<cstdio>
#define LL long long
#define Re register LL
const int P=998244353,N=1e6+5;
LL T,a,b,f,opt,cnt,jc[N*2+5],dp[205][205],S[105][105];
inline void in(Re &x){
x=f=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
if(f)x=-x;
}
inline LL mi(Re x,Re k){
Re ans=1;
while(k){
if(k&1)ans=(ans*x)%P;
x=(x*x)%P;k>>=1;
}
return ans%P;
}
inline LL niv(Re x){return mi(x,P-2);}
inline LL c(Re m,Re n){
if(n<m)return 0;
if(n<P)return jc[n]*niv(jc[m])%P*niv(jc[n-m])%P;
return c(m/P,n/P)*c(m%P,n%P)%P;
}
inline void Stirling(){
for(Re i=0;i<=100;++i)S[i][i]=1;
for(Re i=1;i<=100;++i)
for(Re j=1;j<=100;++j)
S[i][j]=(S[i-1][j-1]+S[i-1][j]*j%P)%P;
}
inline void DP(){
dp[0][0]=1;
for(Re i=1;i<=200;++i)
for(Re j=1;j<=i;++j)
dp[i][j]=(dp[i-j][j]+dp[i-1][j-1])%P;
}
inline LL Catalan(Re n){return c(n,n<<1)*niv(n+1)%P;}
int main(){
// freopen("cat.in","r",stdin);
// freopen("cat.out","w",stdout);
jc[0]=1;for(Re i=1;i<=N*2;i++)jc[i]=jc[i-1]*i%P;
in(T);Stirling();DP();
while(T--){
in(opt),in(a),in(b);
if(opt==1)printf("%lld
",mi(b,a));
else if(opt==2)printf("%lld
",c(b-1,a-1));
else if(opt==3)printf("%lld
",c(b-1,a+b-1));
else if(opt==4)printf("%lld
",S[a][b]);
else if(opt==5)printf("%lld
",jc[b]*S[a][b]%P);
else if(opt==6){
Re ans=0;
for(Re i=1;i<=b;++i)(ans+=S[a][i])%=P;
printf("%lld
",ans);
}
else if(opt==7)printf("%lld
",dp[a+b][b]);
else if(opt==8)printf("%lld
",dp[a][b]);
else if(opt==9)printf("%lld
",Catalan(a));
}
}