73.Acwing基础课第887题-简单-求组合数Ⅲ

73.Acwing基础课第887题-简单-求组合数Ⅲ

题目描述

\(给定 n 组询问,每组询问给定两个整数 a,b,请你输出 C^b_amod\ p的值\)

输入格式

\(第一行包含整数 n\)

\(接下来 n 行,每行包含一组 a, b和p\)

输出格式

共 n 行,每行输出一个询问的解。

数据范围

\(1≤n≤20\)
\(1≤b≤a≤10^{18}\)
\(1≤p≤10^{5}\)

输入样例:

3
5 3 7
3 1 5
6 4 13

输出样例:

3
3
2

代码:

// 包含基础输入输出、算法头文件
#include <iostream>
#include <algorithm>

using namespace std;

// 定义长整型别名:处理超大数(a/b可达1e18,需用LL存储)
typedef long long LL;

// 快速幂函数:计算 (a^k) mod p 的结果(费马小定理求逆元的核心)
// 参数:a-底数,k-指数,p-模数(本题中p是质数)
int qmi(int a, int k, int p)
{
    int res = 1; // 初始化结果为1(乘法单位元)
    // 二进制分解指数k,时间复杂度O(logk)
    while (k)
    {
        // k&1:判断k的二进制最低位是否为1(等价于k%2==1)
        if (k & 1) res = (LL)res * a % p; // 结果乘当前底数,转LL防溢出
        a = (LL)a * a % p; // 底数平方,转LL防溢出
        k >>= 1; // 指数右移一位(等价于k /= 2)
    }
    return res; // 返回 (a^k) mod p
}

// 组合数计算函数:求 C(a,b) mod p(a,b < p,p是质数)
// 公式:C(a,b) = a*(a-1)*...*(a-b+1) / (b!) mod p
// 模运算中除法转乘逆元:除以i等价于乘i^(p-2) mod p
int C(int a, int b, int p)
{
    // 边界条件:选的数比总数多,组合数为0
    if (b > a) return 0;

    int res = 1;
    // 循环b次,计算分子:a*(a-1)*...*(a-b+1),分母:1*2*...*b
    // 技巧:边乘分子边乘分母的逆元,避免先算大数再取模
    for (int i = 1, j = a; i <= b; i ++, j -- )
    {
        res = (LL)res * j % p; // 乘分子项(j从a递减到a-b+1)
        // 乘分母项的逆元(i从1递增到b),逆元用快速幂求
        res = (LL)res * qmi(i, p - 2, p) % p;
    }
    return res;
}

// Lucas定理核心函数:求 C(a,b) mod p(a,b可达1e18,p是小质数)
// Lucas定理:C(a,b) ≡ C(a%p, b%p) * C(a/p, b/p) mod p
int lucas(LL a, LL b, int p)
{
    // 递归边界:a,b都小于p时,直接用普通组合数公式计算
    if (a < p && b < p) return C(a, b, p);
    // 递归公式:拆分为 C(a%p, b%p) * C(a/p, b/p) mod p
    // 转LL防溢出:C返回int,但相乘可能超int范围
    return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}

int main()
{
    int n; // n:查询的组数
    cin >> n;

    // 处理每组查询
    while (n -- )
    {
        LL a, b; // a:总数;b:选取数(a,b可达1e18)
        int p;   // p:模数(小质数,如1e5以内)
        cin >> a >> b >> p;
        // 调用Lucas定理计算并输出结果
        cout << lucas(a, b, p) << endl;
    }

    return 0;
}
posted @ 2026-04-09 17:19  CodeMagicianT  阅读(2)  评论(0)    收藏  举报