Number theory papers 7-- number of combinations & Lucas Theorem (Lucas) number theory papers 4-- inverse (reciprocal number theory)

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);
}

 

Guess you like

Origin www.cnblogs.com/czc1999/p/11745171.html