组合数—学习笔记
Posted niiick
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了组合数—学习笔记相关的知识,希望对你有一定的参考价值。
定义:
从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定理,要结合中国剩余定理
先坑着= =
以上是关于组合数—学习笔记的主要内容,如果未能解决你的问题,请参考以下文章