在acm竞赛中,组合数取模的题目还是经常会见到的,所以这是有必要掌握的一个算法。我本人就因为这个东西而被坑了很多次了= =之前的博客也都扯过了,就不多说了,下面进入正题。
(1)杨辉三角求组合数
杨辉三角这个东西应该都不陌生,三角的两边始终为一,之后向下累加,组成杨辉三角。
而同样的,这个三角也可以看作一个组合数的表格,比如第三行中,依次可看作为C(3,0),C(3,1),C(3,2),C(3,3)。而通过这个,我们也可以发现一个组合数的规律,即是C(n,m)=C(n-1,m-1)+C(n-1,m)。所以,对于一些数据比较小的题目,我们可以通过用杨辉三角打表求组合数的方法得到需要的数。
int Combination(int n)
{
int i,j;
a[0][0]=1;
for(i=0;i<=n;i++)
{
a[i][0]=a[i][i]=1;
for(j=1;j<i;j++)
{
a[i][j]=(a[i-1][j-1]+a[i-1][j])%mod;
}
}
return 0;
}
博客题目链接:http://blog.youkuaiyun.com/lmhacm/article/details/52704938
(2)逆元求组合数
而对于一些题目,给出的数据范围很大,就不能用打表的方式来做,需要直接求出组合数才行,我们根据组合数的定义,可以知道组合数的直接求法。
但是这种求法也存在着一定的问题,假如数字太大,可能会爆出long long的内存范围,但是取模处理对于除法并不适用,我们无法将直接看作
,所以,我们这里需要用求逆元的方式,将这个除法式子改为乘法式子,才可以进行分配开的取模运算。
这里逆元指乘法逆元,假设b存在乘法逆元,即与m互质(充要条件)。设c是b的逆元,即b∗c≡1(mod p),那么有a/b=(a/b)∗1=(a/b)∗b∗c=a∗c(mod p),即,除以一个数取模等于乘以这个数的逆元取模。这样就可以将除法计算变为乘法计算,进而进行取模就可以避开出现精度的问题。
如何求逆元也有很多方法:
1、当a和p互质时,逆元求解一般利用扩展欧几里得算法。
2、当p为质数的时候直接使用