Combination number review notes

Posted by yaatra on Wed, 09 Mar 2022 14:54:13 +0100

Groups and numbers are as follows according to the parameter data range:

Contains n groups of data, each group of data input two numbers a and b;

The first case: the data range of a and b is relatively small

Range: 1 ≤ n ≤ 100001 ≤ n ≤ 10000,1 ≤ b ≤ a ≤ 2000;

In this simplest case, use the formula directly:  = Preprocessing, and then directly access the subscript of the answer;

#include<iostream>

using namespace std;

const int N = 2010;
int c[N][N];
const int mod = 1e9 + 7;

int main()
{
    for(int i = 0;i <= 2000;i ++)
    for(int j = 0;j <= i;j ++)
    if(!j)c[i][j]=1;
    else c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
    int n;
    cin>>n;
    while(n--)
    {
        int a,b;
        cin>>a>>b;
        cout<<c[a][b]<<endl;
    }
    return 0;
}

The second case: the data range of a and b is relatively large

Range: 1 ≤ n ≤ 100001 ≤ n ≤ 10000,1 ≤ b ≤ a ≤ 1e5;

Practice: in this case, use the formula:It is also to preprocess first and finally subscript the answer, in which Fermat's small theorem is used to find the inverse element;

Proof of Fermat's small theorem:

First, the definition of Fermat's small theorem: if a and p are coprime, then there is

The code is as follows:

#include<iostream>

using namespace std;

const int N = 100010;
int fact[N],infact[N];
int mod = 1e9 + 7;

int qmi(int a,int p,int mod)
{
    int sum = 1;
    while(p)
    {
        if(p&1)sum = (long long)sum * a%mod;
        p = p >> 1;
        a = (long long)a*a%mod;
    }
    return sum%mod;
}
int main()
{
    fact[0] = 1;infact[0]=1;
    for(int i = 1;i < N;i ++)
    {
        fact[i] = (long long)fact[i-1]*i % mod;
        infact[i] = (long long)infact[i-1]*qmi(i,mod-2,mod)%mod;
    }
    int n;
    cin >> n;
    while(n--)
    {
        int a,b;
        cin>>a>>b;
        cout<<(long long)fact[a]*infact[b]%mod*infact[a-b]%mod<<endl;
    }
}

Supplement some formulas of congruence equation:

1. If(mod p),(mod p),

Then a+cB + D (mod p) (except addition, subtraction and multiplication, all have the same formula, except Division),(mod p);

2. If, p cannot divide a, i.e. gcd(a,p)=1, then there is b

Prove that:

Lemma: if a and p are coprime, then there is x, y is an integer so that ax+by=1;

First proof lemma:

Consider that all {ax + by | x, y belong to integer}

Assume a minimum integer n;

So exist

Where n must be divided by a;

Otherwise, a = n*q + r < 0 < R < n;

r = 

The third case: there are very few test samples, but the values of a and b are very large;

Range: 1 < = n < = 20; 1<=b<=a<=1e18; 1<=p<=1e5;

Practice: use Lucas theorem

Lucas theorem:

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;


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


int C(int a, int b, int p)
{
    if (b > a) return 0;

    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) % p;
    }
    return res;
}


int lucas(LL a, LL b, int p)
{
    if (a < p && b < p) return C(a, b, p);
    return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}


int main()
{
    int n;
    cin >> n;

    while (n -- )
    {
        LL a, b;
        int p;
        cin >> a >> b >> p;
        cout << lucas(a, b, p) << endl;
    }

    return 0;
}

The fourth case: without mod, the result may be very large

Practice: high precision is required

Decomposition quality factor =

First, preprocess all the quality factors and find out the number of times of quality factors;

Example:

For example, the number of times p is required. First find out how many numerators and denominators there areHow do I subtract the denominator from the p in the numerator, the difference isNumber of;

So a! How manyAnd?

We can get it this way:

Take out all p first, take out all p squares, then take out the third power of p, and so on, all p will be taken out;

So the first step came: sun out all the primes within one to five thousand;

Step 2: find the number of times of each prime number;

Step 3: multiply all quality factors with high-precision multiplication;

The code is as follows:

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;


const int N = 5010;

int primes[N], cnt;
int sum[N];
bool st[N];


void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}


int get(int n, int p)
{
    int res = 0;
    while (n)
    {
        res += n / p;
        n /= p;
    }
    return res;
}


vector<int> mul(vector<int> a, int b)
{
    vector<int> c;
    int t = 0;
    for (int i = 0; i < a.size(); i ++ )
    {
        t += a[i] * b;
        c.push_back(t % 10);
        t /= 10;
    }
    while (t)
    {
        c.push_back(t % 10);
        t /= 10;
    }
    return c;
}


int main()
{
    int a, b;
    cin >> a >> b;

    get_primes(a);

    for (int i = 0; i < cnt; i ++ )
    {
        int p = primes[i];
        sum[i] = get(a, p) - get(a - b, p) - get(b, p);
    }

    vector<int> res;
    res.push_back(1);

    for (int i = 0; i < cnt; i ++ )
        for (int j = 0; j < sum[i]; j ++ )
            res = mul(res, primes[i]);

    for (int i = res.size() - 1; i >= 0; i -- ) printf("%d", res[i]);
    puts("");

    return 0;
}

Author: yxc
 Link: https://www.acwing.com/activity/content/code/content/53401/
Source: AcWing
 The copyright belongs to the author. For commercial reprint, please contact the author for authorization. For non-commercial reprint, please indicate the source.