组合数
转自acwing
1.询问次数大
// c[a][b] 表示从a个苹果中选b个的方案数 for (int i = 0; i < N; i ++ ) for (int j = 0; j <= i; j ++ ) if (!j) c[i][j] = 1; else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
2
首先预处理出所有阶乘取模的余数fact[N],以及所有阶乘取模的逆元infact[N] 如果取模的数是质数,可以用费马小定理求逆元 int qmi(int a, int k, int p) // 快速幂模板 { int res = 1; while (k) { if (k & 1) res = (LL)res * a % p; a = (LL)a * a % p; k >>= 1; } return res; } // 预处理阶乘的余数和阶乘逆元的余数 fact[0] = infact[0] = 1; for (int i = 1; i < N; i ++ ) { fact[i] = (LL)fact[i - 1] * i % mod; infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod; } \
3数据极大(10^18)
若p是质数,则对于任意整数 1 <= m <= n,有: C(n, m) = C(n % p, m % p) * C(n / p, m / p) (mod p) int qmi(int a, int k) // 快速幂模板 { int res = 1; while (k) { if (k & 1) res = (LL)res * a % p; a = (LL)a * a % p; k >>= 1; } return res; } int C(int a, int b) // 通过定理求组合数C(a, b) { int res = 1; for (int i = 1, j = a; i <= b; i ++, j -- ) { res = (LL)res * j % p; res = (LL)res * qmi(i, p - 2) % p; } return res; } int lucas(LL a, LL b) { if (a < p && b < p) return C(a, b); return (LL)C(a % p, b % p) * lucas(a / p, b / p) % p; }