【数学】组合数学 - 排列组合

父级页面:【数学】组合数学

排列

组合

可重排列

可重组合

隔板法

盒子可以为空

隔板法:x个相同的小球,有y个不同的盒子,每个盒子可以为空,求有多少种方案数?把y个不同的盒子视作y-1个不同的隔板,然后把小球视作不同的,全排列有 Ax+y1x+y1 种,然后除以隔板的全排列(隔板之间没有区别),再除以小球的全排列(小球之间也没有区别),最后在两侧再加入两个隔板,然后两个隔板之间的就是这个盒子分配到的球数,也就是 Cx+y1x

隔板法2:Stars and Bars,x个相同的小球,y个不同的盒子,每个盒子可以为空,求有多少种方案数?用y-1个隔板去分隔小球,分隔得到y段可能为空的区间,这个区间就是原本的盒子。由于隔板是相同的,小球也是相同的,所以就是隔板数y-1和小球数x的和,选出y-1个位置来放隔板或者选出x个位置来放小球。(不同的盒子由其顺序确定)。

**注意这里是 Cx+y1x 或者 Cx+y1y1 ,不要写成 Cx+y1x1 了!或者说就不应该想象成盒子数y,应该直接就用隔板数y-1就好了。

盒子可以为空的问题也可以先借y个小球过来,然后用下文盒子非空的方法做,显然是 x+y -1个小球之间选y-1个隔板,然后最后把虚空的小球还回去。

把小球数记为n,盒子数记为m,那么等价于求方程 x1+x2+x3++xm=n,xi0 的解。

盒子必须非空

x个相同的小球,y个不同的盒子,每个盒子至少要分到1个小球。这个问题比上面的简单得多,只需要找y-1个插板插到小球之间的x-1个空位里面,并且一个空位里面最多只有一个插板,所以就是 Cx1y1

但是也可以转化为上面那个问题,先取出y个小球各放1个进盒子里面,然后用盒子可以为空的方法做。

把小球数记为n,盒子数记为m,那么等价于求方程 x1+x2+x3++xm=n,xi1 的解。

这个方法可以进一步推广到盒子内至少有k个小球,那么要借y*k个虚空小球,然后最后再把他们都还回去。当然每个盒子的小球的下限甚至没必要一样。设每个盒子的下限是k_i,那么就先把 sum k_i 个小球都分别放到盒子里面再用盒子非空的方法去做。

整数分拆

小球也相同,盒子也相同,可以有空盒子。相当于整数分拆的问题,不太好算,可以用生成函数去搞

例如4的分拆有4, 3+1, 2+2, 2+1+1, 1+1+1+1, p(4) = 5

(1+x+x2+x3+...)(1+x2+x4+x8+...)(1+x3+x6+x9+...)...

求上面这个多项式的第n项的结果就是n的整数分拆。其中第i个括号表示拆分出多少个数字i,不重不漏。

利用生成函数可以求出诸如:

差分拆:每个数字最多拆出现一次:

4的分拆只有4, 3+1

生成函数就是下面(因为相同的数字要么出现0次要么出现1次,所以变成了二项式):

(1+x)(1+x2)(1+x3)...

奇分拆:拆出来的都是奇数:

4的分拆只有:3+1, 1+1+1+1

(1+x+x2+x3+...)(1+x3+x6+x9+...)(1+x5+x10+x15+...)...

据说奇分拆和差分拆的数量是一样的。不会证明。

常用的求和:

Cnm=Cn1m1+Cn1m
mCnm=nCn1m1

二项式定理

i=0nCni=Cn0+Cn1+Cn2++Cnn=2n
类似求和 i=0n(1)iCni=Cn0Cn1+Cn2+(1)nCnn=0 (奇数项求和=偶数项求和)
i=0n2iCni=3n

利用 CnmCmk=CnkCnkmk ,加上二项式定理,可以得到下式

1Cn1+2Cn2+3Cn3++nCnn=n2n1
i=1iCni=i=1Ci1Cni=i=1CniCi1=i=1Cn1Cn1i1=Cn1i=1nCn1i1=Cn1i=0n1Cn1i=n2n1

12Cn1+22Cn2+32Cn3++n2Cnn=n(n+1)2n2

Cn11Cn22+Cn33++(1)n1Cnnn=1+12+13++1n

(Cn0)2+(Cn1)2+(Cn2)2++(Cnn)2=C2nn

n个球选x个染黑,黑球之间位置差至少为k的方案:在n-(x-1)(k-1)里面选x个黑球,染黑之后在前x-1个黑球后紧跟k-1个白球,得一一对应。

圆排列:n个不同的球,取m个进行圆排列,先用组合数取出m个,然后规定圆的开头是最小的元素,那么剩下的元素可以任意排列,故答案为 CnmAm1m1=n!(nm)!m!(m1)!=n!(nm)!m=Anmm

错位排列

copy    ll D[MAXN];
    void initD(int n) {
        ASSERT(1 <= n && n <= MAXN && n < MOD);
        D[0] = 1, D[1] = 0;
        for(int i = 2; i <= n; ++i) {
            if(i & 1) {
                D[i] = (1LL * i * D[i - 1] - 1) % MOD;
                if(D[i] < 0) D[i] += MOD;
            } else
                D[i] = (1LL * i * D[i - 1] + 1) % MOD;
        }
    }
posted @   purinliang  阅读(170)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示