The number of combinations
Is the number of permutations of combinations of high school knowledge, the number of combinations to solve C (n, m), i.e., removed from the number m of the n th program of the same article.
Solving way
Solving formula: $ C ^ {m} _ {n} = \ dfrac {n!} {M \ left (nm \ right)!!} $
Nature 1: $ C ^ {m} _ {n} = C_ {n} ^ {nm} $
性质 2: $ C ^ {m} _ {n} = C ^ {m-1} _ {n-1} ^ {-i + C} _ {n m-1} $
Recursive play table
The nature of the 2: $ C ^ {m} _ {n} = C ^ {m-1} _ {n-1} -i + C ^ {m} _ {n-1} $
Particularly large number of combinations calculated, are often required to take more than, here take $ P = 1e9 + 7 $. Time complexity $ O (n ^ 2) $
const int P = 1e9 + 7; #define N 1000 int comb[N][N]; int main() { for (int i = 0; i < N; i++) { comb[i][0] = comb[i][i] = 1; for (int j = 1; j < i; j++) { comb[i][j] = comb[i - 1][j] + comb[i - 1][j - 1]; comb[i][j] %= P; //cout << comb[i][j] << endl; } } }
Inverse method
Because most of the remainder have questions, you can use inverse principle (I did not ask for the subject of their own to find a large prime number as P, can also be done using inverse)
Linear Recursive inversing
When there $ a ^ $ p $ is a prime number {- 1} = (p- [p / a]) \ cdot (p \% a) ^ {- 1} \% p $
Factorial inverse element
According to the general formula: $ C ^ {m} _ {n} = \ dfrac {n!} {M \ left (nm \ right)!!} $, There $ C ^ {m} _ {n} = n \! cdot inv [m!] \ cdot inv [(nm)!] $
设 $finv(i)=inv(i\ !)$
则根据:$finv(i-1)=\frac{1}{\ (i-1)\ !}=\frac{1}{i\ !}\times i =finv(i)\times i$
有:$finv(i) = finv(i-1)\times inv(i)$
See: number theory papers 4-- inverse (reciprocal number theory)
Initialization time complexity $ O (n) $, seeking $ C ^ {m} _ {n} $ is $ O (1) $
const int N = 200000 ; const int P = ( int ) 1E9 + . 7 ; int FACT [N + . 5 ], Finv [N + . 5 ], INV [N + . 5 ]; // FACT is factorial, Finv is factorial inverse element void the init () { INV [ . 1 ] = . 1 ; // linear recursion inversing for ( int I = 2 ; I <= N; I ++ ) { inv[i] = (P - P / i) * 1ll * inv[P % i] % P; } fact[0] = Finv[0] = 1; for (int i = 1; i < N; i++) { FACT [I] = FACT [I - . 1 ] * I * 1LL% P; // factorial Finv [I] = Finv [I - . 1 ] * * 1LL INV [I]% P; // factorial inverse element } } int C(int n, int m) {//comb(n, m)就是C(n, m) if (m < 0 || m > n) return 0; return fact[n] * 1ll * Finv[n - m] % P * Finv[m] % P; }
Lucas Theorem
Now we have a new problem, if the n-$ $ $ and $ m is very large, such as seeking $ C_n ^ m \% p \, \ n \ leqslant 10 ^ {18}, m \ leqslant 10 ^ {18}, p \ leqslant ^ {10} $ 9
$C_n^m\ \%\ p = C(n / p, m / p) * C(n\ \%\ p, m\ \%\ p)\ \%\ p$
Or written as a more accurate $ Lucas (n, m) \ \% \ p = Lucas (n / p, m / p) * C (n \ \% \ p, m \ \% \ p) \ \% \ p $
See this proves lucas_ Baidu Encyclopedia , did not look carefully proved right so I do not know .
Written recursively, so short code:
LL Lucas(LL n, LL m, int p){ return m ? Lucas(n/p, m/p, p) * C(n%p, m%p, p) % p : 1; }
Realization depends on the circumstances of the specific C.
When p large , can not play table, with fast power inverse calculation
typedef long long ll; const int N = 1e9 ; const int P = 1e8 + 7; ll quickPower(ll a, ll b) { ll res = 1; a %= P; while (b) { if (b & 1)res = (res % P) * (a % P) % P; a = (a % P) * (a % P) % P; b >>= 1; } return res; } INV LL (LL X) { // X on the inverse element p, p is a prime number return quickPower (X, P - 2 ); } ll C(ll n, ll m) { if (m > n)return 0; ll up = 1, down = 1;//分子分母; for (int i = n - m + 1; i <= n; i++)//龟速乘 up = up * i % P; for (int i = 1; i <= m; i++)//龟速乘 down = down * i % P; return up * inv(down) % P; } ll Lucas(ll n, ll m) { if (m == 0)return 1; return C(n % P, m % P) * Lucas(n / P, m / P) % P; }
when p is small, play table
typedef long long ll; const int N = 1E5; const int P = 99991 ; // get a prime number less than N LL FACT [N + . 5 ], INV [N + . 5 ], Finv [N + . 5 ]; // factorial play table void init() { INV [ . 1 ] = . 1 ; // linear recursion inversing for ( int I = 2 ; I <= N; I ++ ) { inv[i] = (P - P / i) * 1ll * inv[P % i] % P; } fact[0] = Finv[0] = 1; for (int i = 1; i < N; i++) { FACT [I] = FACT [I - . 1 ] * I * 1LL% P; // factorial Finv [I] = Finv [I - . 1 ] * * 1LL INV [I]% P; // factorial inverse element } } ll C(ll n, ll m){//组合数C(n, m) % p if (m > n)return 0; return fact[n] * Finv[n - m] % P * Finv[m] % P; } ll Lucas(ll n, ll m){ return m ? C(n % P, m % P) * Lucas(n / P, m / P) % P : 1; } int main () { init(); cout << Lucas(18, 3); }