注意事项:
涉及以下知识点:
lucas定理推导
java—快速幂—求逆元
题目:
输入:
3
5 3 7
3 1 5
6 4 13
输出:
3
3
2
public class 求组合数_3_lucas定理 {
//p是动态,每次查询p的值都会变化,但是因为p在函数内用的太多了,我们就定义在外面比较好
public static int p;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
while (n-- > 0) {
long a = in.nextLong(), b = in.nextLong();
p = in.nextInt();
System.out.println(lucas(a, b));
}
}
//lucas定理,这东西用的不多,我就不推了,放个链接,人家讲的挺好的
public static long lucas(long a, long b) {
if (a < p && b < p) return C(a, b);
else return C(a%p, b%p) * lucas(a/p, b/p) % p;
}
//根据公式直接推
//举个栗子,C62,从6中选2,也就是6!/2!(6-2)! = 6*5/2*1, 我们不想计算除法,直接用乘法逆元代替,res*6*逆(1)*5*逆(2)
public static long C(long a, long b) {
long res = 1;
for (long i = 1, j = a; i <= b; i++, j--) {
res = res * j % p;
res = res * qmi(i, p-2) % p;
}
return res;
}
//快速幂,原封不动
public static long qmi(long a, long k) {
long res = 1;
while (k > 0) {
if ((k&1) == 1) res = res*a % p;
k >>= 1;
a = a*a % p;
}
return res;
}
}
思路:
lucas:
C
a
b
≡
C
a
%
p
b
%
p
×
C
a
/
p
b
/
p
(
m
o
d
p
)
C_{a}^{b} \equiv C_{a \% p}^{b \% p} \times C_{a / p}^{b / p} \pmod p
Cab≡Ca%pb%p×Ca/pb/p(modp)
组合公式:
C
a
b
=
a
∗
(
a
−
1
)
∗
(
a
−
2
)
∗
…
(
a
−
b
+
1
)
b
!
C^b_{a} = \frac{a * (a - 1) * (a - 2) * … (a - b + 1)}{b!}
Cab=b!a∗(a−1)∗(a−2)∗…(a−b+1)
声明:算法思路来源为y总,详细请见https://www.acwing.com/
本文仅用作学习记录和交流