组合数—学习笔记

定义:

从n个不同元素中取出m(m≤n)个元素的所有组合的个数,叫做从n个不同元素中取出m个元素的组合数,记作$C_{n}^m $,定义式为$C_{n}^m=\frac{n!}{m!(n-m)!}$
*************************

计算:

令 $C(i,0)=C(i,i)=1 (1<= i <= n)$
则有递推式$C(n,m)=C(n-1,m)+C(n-1,m-1)$
证明
对于n个数中当前任意一个数,显然有取与不取两种选择
若取,问题转化为在剩下n-1个数中取m-1个数的方案数,即C(n-1,m-1)
若不取,问题转化为在剩下n-1个数中取m个数的方案数,即C(n-1,m)
利用加法原理即得到递推式

//递推版
for (int i=1;i<=n;++i)
{  
    c[i][0]=c[i][i]=1;
    for(int j=1;j<i;++j)  
    c[i][j]=c[i-1][j]+c[i-1][j-1]; 
}
//递归版
int C(int n,int m)
{
    if(m==0||m==n) return 1;
    else return C(n-1,m-1)+C(n-1,m);
}
//递归记忆化版
int C(int n,int m)
{
    if(m==0||m==n) return 1;
    if(res[n][m]) return res[n][m];
    else return res[n][m]=C(n-1,m-1)+C(n-1,m);
}

单次递归计算复杂度不会超过O(n^2)
递推打表复杂度O(n^2)
*****************************
根据组合数定义式我们可以按如下变形
$$C_{n}^m=\frac{n!}{m!(n-m)!}$$
$$=\frac{(n-m+1)(n-m+2)...(n-m+m)}{12...m}$$
$$=\frac{\frac{ \frac{\frac{(n-m+1)}{1}(n-m+2)}{2}... }{...}*(n-m+m)}{m}$$
有了如上推导,我们就得到了一个复杂度为O(m)得单次递推计算方法

int C(int n,int m)
{
    int ans=1;
    for(int i=1;i<=m;++i)
    ans*=(n-m+i)/i;
    return ans;
} 

组合数拓展

二项式定理

$ (a+b)^n=C_{n}^0a^0b^n+C_{n}^1a^1b^{n-1}+...+C_{n}^na^nb^0=\sum_{k=1}^nC_{n}^ka^kb^{n-k}$

即对于任意二项式$ (a+b)^n$
二项式展开式的第k+1(0<= k <= n) 项的系数为$C_{n}^k$

而该二项式展开式所有n+1个系数的和等于$2^n$
所有偶数项系数的和等于$2^{n-1}$,所有奇数项系数的和亦然
**************************

组合数对素数取膜$C_{n}^m$$mod$ $p$ (p为素数)

对于之前递推递归方法计算当然可以直接边计算边取膜
但如果仅仅这样也不会单独拿出来讲了对吧

对于上述第二种O(m)的计算
由于除法不支持取膜运算律
所以我们可以将除以i改为乘以i的逆元

乘法逆元 求解与应用

int C(int n,int m)
{
    lt ans=1;
    for(int i=1;i<=m;++i)
    ans*=(n-m+i)*inv[i]%p;
    return ans;//inv[i]是i在膜p意义下的逆元
} 

Lucas定理

难道组合数取膜就这些嘛
显然不可能啊
我么们还有特别高级的Lucas定理

$Lucas(n,m)=C(n,m)$%$p$$=C(n$%$p$$,m$%$p$$)*Lucas(n/p,m/p)$%p
边界为$Lucas(i,0)=1$

int C(int n,int m)
{
    int ans=1;
    for(int i=1;i<=m;++i)
    ans*=(n-m+i)*inv[i]%p;
    return ans;
} 

int lucas(int n,int m)
{
    if(m==0) return 1;
    else return C(n%p,m%p)*lucas(n/p,m/p)%p;
}

组合数取膜$C_{n}^m$$mod$ $p$(p不一定为素数)

扩展Lucas定理,要结合中国剩余定理
先坑着= =

猜你喜欢

转载自www.cnblogs.com/niiick/p/8971275.html