java---求组合数(3)---lucas定理(每日一道算法2022.9.23)

注意事项:
涉及以下知识点:
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 CabCa%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(a1)(a2)(ab+1)

声明:算法思路来源为y总,详细请见https://www.acwing.com/
本文仅用作学习记录和交流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值