1 条题解

  • 0
    @ 2025-12-11 21:07:19

    题目分析

    问题描述: 给定字符串长度 nn 和字符集大小 KK,求有多少个长度为 nn 的字符串,其满足:该字符串或者是回文串,或者其某个循环移位是回文串(即“循环回文串”)。答案对 modmod 取模。

    数据范围n1018n \le 10^{18}T10T \le 10,模数 pp 可能是大质数。

    算法核心思路

    这道题的本质是运用 Burnside引理/Polya定理 的思想配合 容斥原理 来计数,同时因为 nn 很大,需要使用 Pollard's Rho 算法进行质因数分解。

    1. 数学推导

    一个字符串 SS 被称为循环回文串,当且仅当它属于某个“回文项链”。 我们需要计算长度为 nn 的循环回文串的数量。这可以通过枚举循环节长度(即 nn 的因子 dd)来解决。

    根据相关数学结论(基于 Burnside 引理的变体),答案的形式涉及到对 nn 的所有因子进行遍历求和。代码中 dfs 函数实际上是在计算如下公式(经过化简):

    $$\text{Ans} = \sum_{d | n} \left( K^{\lceil d/2 \rceil} \times \text{val}(d) \times \text{coeff}(n/d) \right) $$

    其中:

    • dd:当前枚举的因子(代码中的 p)。
    • Kd/2K^{\lceil d/2 \rceil}:长度为 dd 的回文串数量。代码中的 g(p) 函数计算的就是这个值。
      • 如果 dd 是偶数,回文串前半部分确定后半部分,数量为 Kd/2K^{d/2}
      • 如果 dd 是奇数,中间一位也是自由的,数量为 K(d+1)/2K^{(d+1)/2}
    • val(d)\text{val}(d):对于长度 dd 的回文串,其产生的不同循环移位数量的贡献因子。
      • 代码中体现为 (p & 1 ? p : p >> 1)
      • dd 为奇数,贡献为 dd
      • dd 为偶数,贡献为 d/2d/2。这是因为偶数长度的回文串在循环移位视角下存在对称性导致的重复(例如 abba 循环移位只有 2 种本质不同的回文形态,或者在项链计数中的特殊权重)。
    • coeff(n/d)\text{coeff}(n/d):这是一个容斥系数,用于处理非本原(primitive)串的重复计数问题。
      • 在代码的 dfs 中,变量 t 维护了这个系数。
      • 对于 n/dn/d 的每一个质因子 qq,系数乘以 (1q)(1-q)
      • 如果 dd 包含某质因子 qq 的次数与 nn 相同(即 n/dn/d 不含因子 qq),则系数乘以 11
      • 这实际上是在计算一种类似于欧拉函数 ϕ\phi 的变体,用于筛选出以 dd 为最小循环节的贡献。

    2. 代码实现关键点

    由于 nn 高达 101810^{18},直接 O(n)O(n)O(n)O(\sqrt{n}) 枚举都是不可行的。

    1. 大数分解 (Pollard's Rho)

      • 为了获取 nn 的因子,代码使用了 Miller-Rabin 素性测试 (MR) 和 Pollard's Rho 启发式分解算法 (PR)。
      • init 函数将 nn 分解为 p1e1p2e2p_1^{e_1} p_2^{e_2} \dots,存储在数组 a (质数) 和 b (指数) 中。
    2. DFS 枚举因子

      • 利用分解后的质因数,通过 dfs 递归生成 nn 的所有因子 dd
      • 相比直接遍历 1n1 \sim \sqrt{n},直接利用质因数生成因子的效率极高(对于 101810^{18} 内的数,因子个数通常不多)。
    3. 光速幂 (分块预处理)

      • 在计算 Kd/2K^{\lceil d/2 \rceil} 时,指数可能很大。普通的快速幂 ksmO(logn)O(\log n) 的。
      • 代码使用了 分块预处理 策略(类似于 Baby-step Giant-step 的思想)来优化幂运算。
      • mi0, mi1, mi2, mi3 分别预处理了 KK202142^0 \dots 2^{14}, 2152292^{15} \dots 2^{29} 等范围的幂。
      • 这样可以将单次幂运算的时间复杂度从 O(logn)O(\log n) 降至 O(1)O(1),极大地加速了 DFS 过程中的计算。
    4. __int128

      • 由于模数 modmod 接近 10910^9 或更大,中间乘法运算会爆 long long,因此使用了 __int128 (i7) 来保证取模前的精度。

    题解总结

    步骤:

    1. 读入 n,K,modn, K, mod
    2. 使用 Pollard's Rho 算法对 nn 进行质因数分解。
    3. 预处理 KK 的幂次表,将 64 位整数拆分为 4 个 16 位的段,实现 O(1)O(1) 查询 Kx(modmod)K^x \pmod{mod}
    4. 使用 DFS 根据质因数搜索 nn 的所有因子 pp
    5. 在搜索过程中,根据公式 $\text{Ans} += g(p) \times \text{val}(p) \times \text{coeff}(n/p)$ 累加答案。
      • 其中系数 t 的更新逻辑为:若当前质因子未选满(即 n/pn/p 含有该质因子),则 t *= (1 - prime);否则 t *= 1
    6. 输出最终累加的答案。

    复杂度分析:

    • 分解质因数:O(n1/4)O(n^{1/4}) 期望复杂度。
    • DFS:复杂度取决于 nn 的因子个数,对于 101810^{18} 范围内的数,因子个数上限很少(约 10510^5 量级),配合 O(1)O(1) 的幂运算,完全可以在时限内通过。

    这份代码是解决此类大数数论计数问题的标准且高效的模板。

    • 1

    信息

    ID
    6136
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者