组合数的计算以及组合数对p取余后结果的计算
Posted hi3254014978
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了组合数的计算以及组合数对p取余后结果的计算相关的知识,希望对你有一定的参考价值。
前奏:统计 n! 中的所有质因子中pi的个数
普通方法:复杂度O(nlogn), 当n为10的18次方无法承受
// 复杂度O(nlogn), n为10的18次方无法承受 int cal(int n, int p){ int ans = 0; for (int i = 2; i <= n; i++){ int temp = i; while (temp % p == 0){ ans++; temp /= p; // temp除以p } } return ans; }
改进后的方法:复杂度只有O(logn)
int cal(int n, int p){ int ans = 0; while (n){ ans += n / p; // 累加 n / p^k n /= p; // 相当于分母多乘一个 p } return ans; }
1. 组合数的计算(如果只需计算一个组合数则用法三,如果计算很多个组合数则用法二)
法一:通过定义计算
long long C(long long n, long long m){ long long ans = 1; for (long long i = 1; i <= n; i++){ ans *= i; } for (long long i = 1; i <= m; i++){ ans /= i; } for (long long i = 1; i <= n - m; i++){ ans /= i; } return ans; }
法二:通过递推式计算
int res[100][100]; // 用于存放组合数的值 // 法二:通过递推式计算 long long C(long long n, long long m){ if (n == 0 || m == n) return 1; if (res[n][m] != 0) return res[n][m]; return res[n][m] = C(n - 1, m) + C(n - 1, m - 1); // 赋值给res[n][m]并返回 }
把所有组合数都计算出来
// 把所有组合数都计算出来 const int n = 60; void calC(){ for (int i = 0; i <= n; i++){ res[i][0] = res[i][i] = 1; // 初始化边界 } for (int i = 2; i <= n; i++){ for (int j = 0; j <= i / 2; j++){ res[i][j] = res[i - 1][j] + res[i - 1][j - 1]; // 递推计算C(i, j) res[i][i - j] = res[i][j]; // C(i, i - j) = C(i, j) } } }
法三:定义变形,复杂度O(m)(推荐)
long long C(long long n, long long m){ long long ans = 1; for (int i = 1; i <= m; i++){ ans = ans * (n - m + i) / i; // 注意一定要先乘再除 } }
2. 计算C(n, m) % p
递归
// 递归 int res[1010][1010] = { 0 }; int C(int n, int m, int p){ if (m == 0 || m == n) return 1; if (res[n][m] != 0) return res[n][m]; // 已经有值 return res[n][m] = (C(n - 1, m, p) + C(n - 1, m - 1, p)) % p; // 赋值后返回 }
非递归
void CalC(int n, int p){ for (int i = 0; i <= n; i++){ res[i][0] = res[i][i] = 1; // 初始化边界 } for (int i = 2; i <= n; i++){ for (int j = 0; j <= i; j++){ res[i][j] = (res[i - 1][j] + res[i - 1][j - 1]) % p; res[i][i - j] = res[i][j]; } } }
以上是关于组合数的计算以及组合数对p取余后结果的计算的主要内容,如果未能解决你的问题,请参考以下文章