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