1) based on the following formula, directly calculate
C (n, m) mod p = N * ''' * (N-m + 1)/(1 * ''' * m) mod p
Calculate the number of P in the NN, denominator mm, and the remainder of P. If the number of P in the numerator is greater than the number of P in the denominator, the result is 0,
If not, the original formula is NN/mm mod P (NN, P) = 1, (mm, P) = 1
At this time, how to find the reverse element becomes crucial. There are two solutions below.
2) Lucas theorem: used to evaluate the value of C (n, m) mod P, and P is a prime number.
Description:
Lucas (n, m, p) = C (n % P, M % P) * Lucas (N/P, M/P, P)
Lucas (n, 0, P) = 1;
While
C (a, B) = A * (A-1) * ''' * (a-B + 1)/(1*2 * ''' * B) % P,
The numerator is aa denominator and BB, So C (a, B) = AA/BB % P (the same as above)
At this point, the reverse yuan method is also very important. The reverse yuan method will be explained as follows.
Supplementary knowledge: reverse Element Method
(A/B) mod p = A * (B inverse) mod p
B * x = 1 (mod p) x is the reverse element of B.
The inverse B can be obtained using the Extended Euclidean or Euler's function:
1). Extended Euclidean: B * x + p * y = 1 has a solution, and X is what we want
2 ). euler's function: B ^ (p-1) = 1 (mod P), so B * B ^ (P-2) = 1 (mod P), So X = B ^ (P-2)
To sum up, method 1 can be regarded as brute force computing, while method 2 only converts a large number into a number, and then uses method 1 for calculation, which reduces the time.
Method 1: Calculate directly. The Code is as follows:
#include<stdio.h>
#define LL long long
int pnum, x, y;
int getMultMod(int start, int end, int p) {
int i, j;
LL res;
for (i = start, res = 1, pnum = 0; i <= end; i++) {
if (i % p == 0) {
j = i;
while (j % p == 0) {
pnum++;
j /= p;
}
res = res * j % p;
} else {
res = res * i % p;
}
}
return (int) (res % p);
}
void extend_gcd(int a, int b) {
int xx;
if (b == 0) {
x = 1, y = 0;
return;
}
extend_gcd(b, a % b);
xx = x;
x = y, y = xx - a / b * y;
}
void solve(int n, int m, int p) {
int a, b, apnum, bpnum;
LL res;
a = getMultMod(n - m + 1, n, p);
apnum = pnum;
b = getMultMod(1, m, p);
bpnum = pnum;
if (apnum > bpnum) {
puts("0");
return;
} else {
extend_gcd(b, p);
res = (LL) x;
res = (res % p + p) % p;
res = res * a % p;
printf("%I64d\n", res);
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
#endif
int t, n, m, p;
scanf("%d", &t);
while (t--) {
scanf("%d %d %d", &n, &m, &p);
solve(n, m, p);
}
return 0;
}
You can rewrite several methods based on different reverse elements as follows:
int modular_exp(int a, int b, int p) {
LL res, temp;
res = 1 % p, temp = a % p;
while (b) {
if (b & 1) {
res = res * temp % p;
}
temp = temp * temp % p;
b >>= 1;
}
return (int) res;
}
void solve(int n, int m, int p) {
int a, b, apnum, bpnum;
LL res;
a = getMultMod(n - m + 1, n, p);
apnum = pnum;
b = getMultMod(1, m, p);
bpnum = pnum;
if (apnum > bpnum) {
puts("0");
return;
} else {
res = modular_exp(b, p - 2, p);
res = res * a % p;
printf("%I64d\n", res);
}
}
Method 2: using the Lucas theorem, the Code is as follows:
#include<stdio.h>
#define LL long long
int x, y;
void extend_gcd(int a, int b) {
int xx;
if (b == 0) {
x = 1, y = 0;
return;
}
extend_gcd(b, a % b);
xx = x;
x = y, y = xx - a / b * y;
}
int C(int a, int b, int p) {
int i;
LL resa, resb, res;
if (b > a) {
return 0;
}
for (i = 0, resa = 1, resb = 1; i < b; i++) {
resa = resa * (a - i) % p, resb = resb * (b - i) % p;
}
extend_gcd(resb, p);
res = (LL) x;
res = (res % p + p) % p;
res = res * resa % p;
return (int) res;
}
void solve(int n, int m, int p) {
int a, b;
LL res;
res = 1;
while (n || m) {
a = n % p, b = m % p;
res = res * C(a, b, p) % p;
n /= p, m /= p;
}
printf("%I64d\n", res);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
#endif
int t, n, m, p;
scanf("%d", &t);
while (t--) {
scanf("%d %d %d", &n, &m, &p);
solve(n, m, p);
}
return 0;
}
Based on different reverse elements, the preceding methods can be rewritten as follows:
int modular_exp(int a, int b, int p) {
LL res, temp;
res = 1 % p, temp = a % p;
while (b) {
if (b & 1) {
res = res * temp % p;
}
temp = temp * temp % p;
b >>= 1;
}
return (int) res;
}
int C(int a, int b, int p) {
int i;
LL resa, resb, res;
if (b > a) {
return 0;
}
for (i = 0, resa = 1, resb = 1; i < b; i++) {
resa = resa * (a - i) % p, resb = resb * (b - i) % p;
}
res = modular_exp(resb, p - 2, p);
res = res * resa % p;
return (int) res;
}
Summary: The methods involved in this type of problem include the inverse element method (Extended Euclidean algorithm, knowledge of Euler's functions (involving the return of large numbers), the Lucas theorem, and the Group Union number.