组合数的几种计算方法
2017-09-07 14:20
274 查看
组合数一种是OI中比较常用的知识
除了实际的分析之外,我们要考虑的,就是如何快速计算组合数
下面介绍几种常用的计算组合数的方法
如果要对质数P取模,就是这样:
其中inverse是i对P的逆元,inverse(i)=i^(P-2) 【用到快速幂】
边界:C(i,0)=C(i,i)=1
这个递推式用到了动态规划的思想,对于第m个物品,有取和不取两种情况
可以在O(n^2)的时间内算出所有的C(n,m)
Lucas定理解决的是n,m比较大而p是小于100000质数
简而言之就是Lucas(n,m)=C(n%p,m%p)*Lucas(n/p,m/p)%p;
其中组合数C是用任意一种计算10五次方内取模的组合数计算
比如可以预处理阶乘fac[i],然后直接C(n,m)=fac
*quickpow(fac[n-m]*fac[m],p-2)%p;
或者O(n)套公式直接算也可以
要注意n可能小于m,因为是取模后的结果,这个时候返回0【不然会RE】
配合Lucas定理,由于n和m都在10^5范围内,使用预处理阶乘的方法再好不过了:
其实就是直接套公式,只不过使用了 预处理阶乘+逆元,查询复杂度O(log100000),非常低
除了实际的分析之外,我们要考虑的,就是如何快速计算组合数
下面介绍几种常用的计算组合数的方法
朴素公式法
顾名思义,直接套公式int C(int n,int m){ int ans=1; for(int i=1;i<=m;i++) ans=ans*(n-m+i)/i; return ans; }
如果要对质数P取模,就是这样:
int C(int n,int m){ int ans=1; for(int i=1;i<=m;i++) ans=(LL)ans*(n-m+i)*inverse(i)%P; return ans; }
其中inverse是i对P的逆元,inverse(i)=i^(P-2) 【用到快速幂】
递推式法
C(n,m)=C(n-1,m-1)+C(n-1,m)边界:C(i,0)=C(i,i)=1
这个递推式用到了动态规划的思想,对于第m个物品,有取和不取两种情况
可以在O(n^2)的时间内算出所有的C(n,m)
void cal(){ C[0][0]=1; for(int i=1;i<=n;i++){ C[i][0]=C[i][i]=1; for(int j=1;j<=(i>>1);j++){ C[i][j]=C[i][i-j]=(C[i-1][j-1]+C[i-1][j])%P; } } }
Lucas定理
对于n和m比较大(<=10^18)的组合数,就要用到LUCAS定理啦Lucas定理解决的是n,m比较大而p是小于100000质数
简而言之就是Lucas(n,m)=C(n%p,m%p)*Lucas(n/p,m/p)%p;
其中组合数C是用任意一种计算10五次方内取模的组合数计算
比如可以预处理阶乘fac[i],然后直接C(n,m)=fac
*quickpow(fac[n-m]*fac[m],p-2)%p;
或者O(n)套公式直接算也可以
要注意n可能小于m,因为是取模后的结果,这个时候返回0【不然会RE】
LL Lucas(LL n,LL m){ if(n<m||!m) return 1; return C(n%P,m%P)*Lucas(n/P,m/P)%P; }
配合Lucas定理,由于n和m都在10^5范围内,使用预处理阶乘的方法再好不过了:
预处理阶乘法
其实就是直接套公式,只不过使用了 预处理阶乘+逆元,查询复杂度O(log100000),非常低void cal(){ fac[0]=1; for(int i=1;i<=P;i++) fac[i]=fac[i-1]*i%P; } inline LL qpow(LL a,LL b){ LL ans=1; for(;b;b>>=1,a=a*a%P) if(b&1) ans=ans*a%P; return ans; } inline LL C(LL n,LL m){ if(n<m) return 0; return fac *qpow(fac[n-m]*fac[m]%P,P-2)%P; }
相关文章推荐
- 计算组合数的几种方法
- 组合数的几种计算方法
- 大数量级组合数的快速计算方法
- 乘法逆元的几种计算方法
- 句子相似度计算的几种方法
- [组合数]求组合数的几种方法总结
- [组合数]求组合数的几种方法总结
- php中计算时间差的几种方法
- 组合数的两种计算方法(递推,对数)
- php中计算时间差的几种方法
- php中计算时间差的几种方法
- [组合数]求组合数的几种方法总结
- php中计算时间差的几种方法
- [转]关于日期天数计算的几种方法
- 回顾基础知识——实现阶乘计算的几种方法
- c++ 在windows下获取时间和计算时间差的几种方法总结
- php中计算时间差的几种方法
- [转]关键链方法的几种缓冲长度计算方法
- c/c++在windows下获取时间和计算时间差的几种方法总结
- 计算PI(π)的几种方法