P10580 [蓝桥杯 2024 国 A] gcd 与 lcm 解题报告


解题报告: P10580 [蓝桥杯 2024 国 A] gcd 与 lcm

1. 问题分析与转化

题目核心

我们需要找到满足以下两个条件的、长度为 \(n\) 的序列 \(A = (a_1, a_2, \cdots, a_n)\) 的数量:

  1. 最大公约数 gcd(A) = x
  2. 最小公倍数 lcm(A) = y

初步观察

  • 既然序列的最大公约数是 \(x\),那么序列中的每一个数 \(a_i\) 都必须是 \(x\) 的倍数。
  • 既然序列的最小公倍数是 \(y\),那么序列中的每一个数 \(a_i\) 都必须是 \(y\) 的约数。
  • 综合这两点,每个 \(a_i\) 既是 \(x\) 的倍数也是 \(y\) 的约数。这也意味着 \(x\) 必须是 \(y\) 的约数(即 \(y\) 能被 \(x\) 整除)。题目保证了有解,所以这个条件一定成立。

关键转化

为了简化问题,我们对序列中的每个数 \(a_i\) 都除以 \(x\)。设一个新的序列 \(B = (b_1, b_2, \cdots, b_n)\),其中 \(b_i = \frac{a_i}{x}\)。现在我们来分析新序列 \(B\) 需要满足什么条件:

  1. 最大公约数条件:
    gcd(a_1, ..., a_n) = gcd(x*b_1, ..., x*b_n) = x * gcd(b_1, ..., b_n) = x
    这要求 gcd(b_1, ..., b_n) = 1

  2. 最小公倍数条件:
    lcm(a_1, ..., a_n) = lcm(x*b_1, ..., x*b_n) = x * lcm(b_1, ..., b_n) = y
    这要求 lcm(b_1, ..., b_n) = y / x

现在,原问题就成功转化为了一个更简洁的新问题:
求有多少个长度为 \(n\) 的序列 \(B\),使得其最大公约数为 \(1\),最小公倍数为 \(y/x\)

2. 核心思想:质因数分解

处理 gcdlcm 问题,最强大的工具就是质因数分解。这是因为一个数的 gcdlcm 可以通过它每个质因子的指数来独立确定。

  • gcd 取的是各数质因子指数的最小值
  • lcm 取的是各数质因子指数的最大值

我们令 \(t = y/x\),并对 \(t\) 进行质因数分解:\(t = p_1^{k_1} \cdot p_2^{k_2} \cdots p_m^{k_m}\)

对于序列 \(B\) 中的每一个数 \(b_i\),我们也可以分析其质因子的指数。对于 \(t\) 的任意一个质因子 \(p_j\),我们设 \(e_{ij}\)\(p_j\)\(b_i\) 中的指数。

那么,新问题的两个条件可以被分解到每一个质因子上:

  1. gcd(B) = 1 \(\implies\) 对于任意质因子 \(p_j\),指数的最小值为 0。即 min(e_{1j}, e_{2j}, ..., e_{nj}) = 0
  2. lcm(B) = t \(\implies\) 对于任意质因子 \(p_j\),指数的最大值\(k_j\)。即 max(e_{1j}, e_{2j}, ..., e_{nj}) = k_j

由于每个质因子 \(p_j\) 的指数如何分配是相互独立的,我们可以分别计算出满足条件的指数分配方案数,然后将它们全部乘起来,得到最终答案。

3. 单个质因子的求解:容斥原理

现在,我们只关注一个质因子,比如 \(p_1\)(为了方便,我们简写为 \(p\)),它在 \(t\) 中的指数是 \(k_1\)(简写为 \(k\))。
我们需要为序列 \(b_1, \dots, b_n\) 分配 \(p\) 的指数 \(e_1, \dots, e_n\)

由于每个 \(b_i\) 都必须是 \(t\) 的约数,所以 \(p\)\(b_i\) 中的指数 \(e_i\) 只能取 0, 1, ..., k 之间的一个整数。

我们的目标是找到满足下面两个条件的指数序列 \((e_1, \dots, e_n)\) 的数量:

  1. 至少有一个 \(e_i = 0\) (保证 gcd 对应的质因子指数为0)
  2. 至少有一个 \(e_i = k\) (保证 lcm 对应的质因子指数为k)

直接计算满足 "至少..." 的问题比较复杂,我们可以使用容斥原理,通过计算其反面来求解。

  • 总情况数 (无任何限制):
    每个 \(e_i\) 都有 \(k+1\) 种选择(从 \(0\)\(k\)),共 \(n\) 个数,所以总方案数是 \((k+1)^n\)

  • 不满足条件1的情况 (破坏gcd):
    即 "没有一个 \(e_i=0\)",等价于 "所有 \(e_i > 0\)"。
    此时每个 \(e_i\) 的取值范围是 \([1, k]\),共 \(k\) 种选择。方案数为 \(k^n\)

  • 不满足条件2的情况 (破坏lcm):
    即 "没有一个 \(e_i=k\)",等价于 "所有 \(e_i < k\)"。
    此时每个 \(e_i\) 的取值范围是 \([0, k-1]\),共 \(k\) 种选择。方案数为 \(k^n\)

  • 同时不满足条件1和2的情况:
    即 "所有 \(e_i > 0\)" 且 "所有 \(e_i < k\)"。
    此时每个 \(e_i\) 的取值范围是 \([1, k-1]\),共 \(k-1\) 种选择。方案数为 \((k-1)^n\)

根据容斥原理,我们想要的答案是:
总数 - (不满足1) - (不满足2) + (同时不满足1和2)
即:

\[(k+1)^n - k^n - k^n + (k-1)^n = (k+1)^n - 2 \cdot k^n + (k-1)^n \]

这就是对于单个质因子 \(p\),其指数的合法分配方案数。

4. 算法实现与总结

综合以上分析,我们的解题步骤如下:

  1. 读入 \(x, y, n\)
  2. 计算 \(t = y/x\)
  3. \(t\) 进行质因数分解,得到所有的质因子 \(p_i\) 及其指数 \(k_i\)
    • 例如,如果 \(t=12=2^2 \cdot 3^1\),我们得到 (p=2, k=2)(p=3, k=1)
  4. 初始化答案 ans = 1
  5. 遍历每一个质因子的指数 \(k_i\)
    • 根据容斥原理公式,计算出该质因子的贡献:count_i = ((k_i+1)^n - 2*k_i^n + (k_i-1)^n)
    • 因为 \(n\) 很大,计算幂次需要使用快速幂算法。
    • 在计算过程中要时刻对 \(998244353\) 取模。特别注意,减法可能产生负数,需要 (a - b + MOD) % MOD 来保证结果为正。
    • 将这个贡献乘到最终答案中:ans = (ans * count_i) % MOD
  6. 输出最终的 ans

代码实现细节

  • getprime(y/x) 函数负责对 \(y/x\) 进行质因数分解,它只需要记录下每个质因子的指数 \(k_i\) 即可,质因子本身是什么不重要。
  • qpow(base, exp) 函数是标准的快速幂模板,用于高效计算 \(base^{exp} \pmod{MOD}\)
  • 主函数循环处理每个询问,按照上述算法流程计算答案。每次循环开始时,注意清空上一次质因数分解的结果。

这个解法的时间复杂度主要瓶颈在于质因数分解,为 \(O(\sqrt{y/x})\)。由于 \(y/x \le 10^9\),这个复杂度是完全可以接受的。

posted @ 2025-07-22 14:53  surprise_ying  阅读(52)  评论(0)    收藏  举报