Walk--Find the number of combinations

Walk

Question: Find the number of combinations C(n, m) (n is down, m is up)
Let’s first understand two little knowledge

Fermat's Lemma

Insert picture description here
This can be used to find the inverse element under special circumstances.


Inverse element

Definition: If a * x = 1(mod p), and gcd(a, p) = 1 (equivalent to a, p are relatively prime), then x is the multiplicative inverse of a in the sense of mod p.

According to the Fermat's little lemma above, we can know that if p is a prime number, then a^(p-1) = 1(mod p). It holds
that a^(p-2) is a modulo p Inverse element (only applicable to blogs where p is a prime number, the next time you add the inverse element)


Use the inverse element to find the division and take the modulus

Division cannot be directly modulo
Theorem: a/b% p = a*x% mod p = 1% p; (x is the inverse element of a in the sense of modulo p)
Proof: a/b * b * x = a * x (mod p) (b * x = 1(mod p) ); In
this way, the division between the number of combinations is solved.


Speaking code in sections:
quick power templates

ll Power(ll x, ll y) {
    
    
    ll n = y, ans = 1, res = x;
    while(n){
    
    
        if(n & 1) ans = ans * res % mod;
        n >>= 1;
        res = res * res % mod;
    }
    return ans%mod;
}

Initialization: Find each factorial (mod p) and the inverse element of each factorial in the sense of mod p.

for(int i=1; i<=N; i++) C[i] = (C[i-1]*i) % mod;
inv[N-1] = Power(C[N-1], mod-2); //费马小引理求逆元。
for(int i=N-2; i>=0; i--) {
    
    
	inv[i] = inv[i+1]*(i+1) % mod; //阶乘逆元递推关系。
}

Explain the recurrence formula of factorial (k!) − 1 (k!)^(-1)(k!)1 meanskkk的 阶乘 的 逆
(k!) - 1 = ((k - 1)! ∗ k) - 1 = (k - 1) - 1 ∗ k - 1 (k!) ^ {- 1} = ((k- 1)! * K) ^ {- 1} = (k-1) ^ {- 1} * k ^ {- 1}(k!)1=((k1)!k)1=(k1)1k1
So:(k!) − 1 ∗ k = ((k − 1)!) − 1 (k!)^{-1}*k = ((k-1)!)^{-1}(k!)1k=((k1)!)1


Number of final solution combinations

ll U(ll x, ll y) {
    
    
	if(y > x || x < 0 || y < 0) return 0;
	if(y == 0 || x == y) return 1;
	//A(x,x) / (A(y,y) * A(x-y,x-y),转化成逆元相乘
	return (C[x] * inv[y]%mod * inv[x-y]) % mod;
}

Total code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const ll N = 2e6+5;
ll C[N] = {
    
    1};
ll inv[N];
ll Power(ll x, ll y) {
    
    
    ll n = y, ans = 1, res = x;
    while(n){
    
    
        if(n & 1) ans = ans * res % mod;
        n >>= 1;
        res = res * res % mod;
    }
    return ans%mod;
}

ll U(ll x, ll y) {
    
    
	if(y > x || x < 0 || y < 0) return 0;
	if(y == 0 || x == y) return 1;
	return (C[x] * inv[y]%mod * inv[x-y]) % mod;
}
int main() {
    
    
    for(int i=1; i<=N; i++) C[i] = (C[i-1]*i) % mod;
    inv[N-1] = Power(C[N-1], mod-2);
    for(int i=N-2; i>=0; i--) {
    
    
    	inv[i] = inv[i+1]*(i+1) % mod; 
	}
    ll t, a, b, temp;
    scanf("%lld", &t);
    while(t--) {
    
    
        scanf("%lld%lld", &a, &b);
        a--, b--;
        a += b;
        printf("%lld\n", U(a, b));
    }
    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_45363113/article/details/106754025