码迷,mamicode.com
首页 > 其他好文 > 详细

小球与盒子

时间:2019-08-18 15:51:21      阅读:80      评论:0      收藏:0      [点我收藏+]

标签:变换   数加   fft   枚举   不能   没有   存在   并且   cpp   

参考:当小球遇上盒子

默认问题:把 n 个小球放到 m 个盒子里,分别有三项要求:

①球是否相同 ②盒子是否相同 ③能否有空盒。

1.球相同,盒子不同,不能有空盒

利用插板法,n 个小球中间会存在 n-1 个空,用 m-1 块板插入这些空中,可以将 n 个小球分为 m 块,因此:
\[ ans=C_{n?1}^{m?1} \]

2.球相同,盒子不同,可以有空盒

我们现在假设有 m+n 个球然后我们用 m-1 块板将它分隔成了 m 块,然后,我们在每一块中都拿出一个小球,那么现在我们剩下 n 个小球,并且也保证了可以有空盒出现的情况,因此:
\[ ans=C_{n+m?1}^{m?1} \]

3.球不同,盒子不同,可以有空盒

每一个球都有 m 种选择,那么总共有 n 个球,因此:
\[ ans=m^n \]

4.球不同,盒子相同,不能有空盒

\[ ans=S2(n,m)={\frac 1 {m!}}*\sum_{k=0}^{m}(-1)^k{C_m^k}*(m-k)^n \]

\(m^n\) 的意思表示的是将\(n\)个球,\(m\)个盒子按照3来放,其中就包括了可能只放了\(m\)个或者\(m-1\)或者\(m-2\)等等的情况,那\((m-1)^n\)中又包括了只放了\(1<=i<=m-1\)的情况,如果说想表示\(m\)个相同盒子,\(n\)个不同球的放置,不能够单纯的靠\(m^n-(m-1)^n\)来实现,因为\(m^n\)包含了两个\((m-1)^n\)而这两个\((m-1)^n\)中所包含的\((m-2)^n\)又会有交集(即可能出现重复),因此需要用到容斥。最后乘\(1/m!\)是为了消除其有序性。

可以用 FFT(快速傅里叶变换)加速

5.球不同,盒子也不同,不能有空盒

与4唯一的不同就是盒子出现的有序性,因此只需要在上一个公式里不除\(m!\)即可
\[ ans=m!*S2(n,m)=\sum_{k=0}^{m}(-1)^k{C_m^k}*(m-k)^n \]

6.球不同,盒子相同,可以有空盒

因为可以有空盒,我们可以枚举每次一共用了几个盒子,然后把相应的第二类斯特林数加起来就可以了,因此:
\[ ans=\sum_{i=1}^mS2(n,i) \]
这种数叫做贝尔数,可以说贝尔数就是其对应的第二类斯特林数之和,贝尔数对应公式:
\[ B_{n+1}=\sum_{k=0}^nC_n^kB_k \]
即枚举包含最后一个元素的集合大小,也可以通过对应的第二类斯特林数求和得到,公式如下:
\[ B_n=\sum_{k=1}^nS2(n,k) \]

7.球相同,盒子相同,可以有空盒

\(f[n][m]\)\(n\) 个球放到 \(m\) 个盒子里的方案数

如果只有一个盘子或者没有小球,方案数自然为 1

如果小球比盒子要少,小球肯定是放不满盒子的,由于盒子相同,可以得到转移 \(f[i][j]=f[i][i]\)

如果小球比盒子要多,就分为将盘子放满和没放满两种情况,即 \(f[i][j]=f[i?j][j]+f[i][j?1]\)

代码:

for(int i=0;i<=n;i++){
    for(int j=1;j<=m;j++){
        if(j==1 || i==0) f[i][j]=1;
        else if(i<j) f[i][j]=f[i][i];   
        else if(i>=j) f[i][j]=f[i-j][j]+f[i][j-1];
    }
}

8.球相同,盒子相同,不能有空盒

有点类似于第一、二种情况之间的关系。

我们先假设在每一个盒子里都放上了一个球,就跟上面的情况一样了。
\[ ans=f[n?m][m] \]

小球与盒子

标签:变换   数加   fft   枚举   不能   没有   存在   并且   cpp   

原文地址:https://www.cnblogs.com/CADCADCAD/p/11372377.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!