ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

数学-求组合数 III - 卢卡斯定理

2022-07-26 20:34:33  阅读:132  来源: 互联网

标签:return get int res 定理 卢卡斯 include III LL


c++

AcWing 887. 求组合数 III

/*
 *  题目描述:
 *      AcWing 887. 求组合数 III
 *      给定 n 组询问,每组询问给定三个整数 a,b,p,其中 p 是质数,请你输出 C(a, b) mod p 的值。
 *      输入格式:
 *      第一行包含整数 n。
 *      接下来 n 行,每行包含一组 a,b,p。
 *      输出格式:
 *      共 n 行,每行输出一个询问的解。
 *      数据范围:
 *      1 ≤ n ≤ 20,
 *      1 ≤ b ≤ a ≤ 10 ^ 18,
 *      1 ≤ p ≤ 10 ^ 5,
 *      数据范围
 *      1 ≤ n, ai ≤ 100
 *  解题思路:
 *      本题主要难点在于卢卡斯定理,剩余部分主要靠逆元来求解。
 *      卢卡斯定理:
 *          C(a, b) % p = C(a / p, b / p) * C(a % p, b % p) % p
 *      其中 p 是质数,看是卢卡斯定理只是一个式子,但是等式右侧第一项是可以递归的。
 *      并且经过分析可知,为 log p 深度,不难感知到 Lucas 定理对算法复杂度的优化。
 *
 *      证明 Lucas Theorem:
 *          首先,证明 C(p, i) % p = 0, 其中 i ∈ [1, p - 1]。
 *              这是因为 p 作为分子,又是质数,无法被消去,因此 C(p, i) 当 i ∈ [1, p - 1] 是 p 倍数。
 *          然后,可知
 *              (1 + x) ^ (sp + q) % p = ((1 + x) ^ p) ^ s * (1 + x) ^ q % p 
 *                                     = (1 + x ^ p) ^ s * (1 + x) ^ q % p
 *              x ^ (tp + r) 的系数等式左侧为 C(sp + q, tp + r)
 *                                等式右侧为 C(s, t) * C(q, r)
 *              C(sp + q, tp + r) % p = C(s, t) * C(q, r) % p
 *              证明完毕。
 *
 */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;

typedef long long LL;
int n;
LL a, b, p;

LL qmi(LL a, LL b, LL c) {
    LL res = 1;
    while (b) {
        if (b & 1) {
            res = res * a % c;
        }
        b >>= 1;
        a = a * a % p;
    }
    return res;
}

LL get_reverse(LL i, LL p) {
    return qmi(i, p - 2, p);
}

LL get_c(LL u, LL v, LL p) {
    LL res = 1;
    for (int i = u; i >= u - v + 1; i -- ) {
        res = res * i % p;
    }
    for (int i = 2; i <= v; i ++ ) {
        res = res * get_reverse(i, p) % p;
    }
    return res;
}


LL get_result(LL a, LL b, LL p) {
    LL u, v;
    int res = 1;
    while (a > 0) {
        u = a % p, v = b % p;
        a /= p, b /= p;
        res = res * get_c(u, v, p) % p;
    }
    return res;
}

int main()
{
    scanf("%d", &n);
    while (n -- ) {
        scanf("%lld%lld%lld", &a, &b, &p);
        printf("%lld\n", get_result(a, b, p));
    }

    return 0;
}


标签:return,get,int,res,定理,卢卡斯,include,III,LL
来源: https://www.cnblogs.com/lucky-light/p/16522514.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有