数学-求组合数 III - 卢卡斯定理
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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)