1 条题解

  • 0
    @ 2025-10-28 9:25:03

    题目理解

    给定一棵 nn 个节点的树,每个节点有一个大写字母。
    再给一个长度为 mm 的模式串 SS
    问有多少有序节点对 u,v\langle u, v \rangle,使得从 uuvv 的简单路径上的字母连成的字符串,恰好等于 SS 重复 kk 次(k1k \ge 1 整数)。


    样例分析

    样例:

    n=11, m=4
    节点上的字母:IODSSDSOIOI
    边:
    1-2, 2-3, 3-4, 1-5, 5-6, 6-7, 3-8, 8-9, 6-10, 10-11
    S = "SDOI"
    

    输出 5。

    说明有 5 条路径的字符串是 SDOI 重复整数次(这里主要是 SDOI 一次,因为 m=4,路径长度 4 的倍数才可能)。


    思路分析

    1. 路径特征

    • 路径长度 LL(边数)必须是 mm 的倍数,设 L=kmL = k \cdot m
    • 路径上第 ii 个节点(从起点 uu 开始数)的字符必须等于 S[imodm]S[i \bmod m]

    2. 统计方法

    • 最直接的想法是枚举所有 O(n2)O(n^2) 路径,不可行。
    • 树上的路径统计问题,常用点分治
    • 在点分治框架下,考虑经过重心 rr 的路径 urvu \to r \to v,将其拆成 uru \to r(反向)和 rvr \to v(正向)两段。
    • 我们需要合并两段路径,使得总长度 lenu+lenv=kmlen_u + len_v = k \cdot m,并且字符串匹配 SS 的重复。

    3. 字符串匹配处理

    • 为了快速判断路径字符串是否匹配 SkS^k,使用字符串哈希
    • 预处理 SS 重复两次的哈希值,方便计算任意 SkS^k 的哈希。
    • 对于 uru \to r 的反向路径,需要反转后与 SS 匹配,可以预处理 SS 的反串的哈希。

    4. 点分治中的匹配规则

    设:

    • AA = uru \to r 的路径字符串(从 uurr 方向),长度为 aa
    • BB = rvr \to v 的路径字符串(从 rrvv 方向),长度为 bb

    那么 uvu \to v 的字符串是 Areverse+BA^{reverse} + B,总长度 a+ba+b

    条件:

    1. (a+b)modm=0(a+b) \bmod m = 0
    2. AreverseA^{reverse} 必须匹配 SS 的某个后缀,BB 必须匹配 SS 的某个前缀,并且 Areverse+BA^{reverse} + B 正好是 SS 的整数倍重复。

    更具体:

    • t=amodmt = a \bmod m
    • 那么 AreverseA^{reverse} 应等于 S[mtm1]S[m-t \ldots m-1](即 SS 的最后 tt 个字符的反向?这里要注意方向),实际上 AreverseA^{reverse} 应当匹配 SS 的前 tt 个字符的反向?需要仔细推导。

    实际上更稳妥的方法:

    • uru \to r 路径,记录哈希时按照从 rruu 方向计算哈希(即正向视为 rur \to u 的字符串),这样 uru \to r 反向就是正序 rur \to u 的字符串的反向,但哈希可以反向计算。
    • 我们预先计算 SS 的正向哈希 HH 和反向哈希 HrevH_{rev}
    • 在点分治时,对从重心 rr 出发到 xx 的路径,记录:
      • 长度 depdep
      • 哈希值 hh(从 rrxx 方向)
      • 反向哈希值 hrevh_{rev}(从 xxrr 方向,即路径反向的哈希)

    合并时:

    • uru \to r 段用反向哈希(因为实际方向是 uru \to r,对应字符串是 rur \to u 的反向)
    • rvr \to v 段用正向哈希
    • 总哈希 = hrev(ur)×Bb+h(rv)h_{rev}(u \to r) \times B^{b} + h(r \to v),其中 bbrvr \to v 的长度。
    • 检查是否等于 H(Sk)H(S^{k}),其中 k=(a+b)/mk = (a+b)/m

    5. 优化

    • 用哈希表存储从重心出发的路径信息(长度模 mm,哈希值,方向等),然后匹配对应的“另一半”路径。
    • 注意去重,保证 uuvv 在重心的不同子树。

    算法步骤

    1. 预处理 SS 重复两次的正向哈希和反向哈希,以及 BlenB^{len} 的幂。
    2. 点分治:
      • 找重心
      • 对每个子树 DFS,记录路径信息(长度,哈希,反向哈希,子树标号)
      • 用哈希表统计当前已遍历子树的路径
      • 遍历新子树时,先查询已存路径中能匹配的路径数,再加入新子树路径
    3. 统计所有经过重心的合法路径数。
    4. 递归处理子树。

    复杂度

    • 点分治 O(nlogn)O(n \log n)
    • 哈希比较 O(1)O(1)
    • 总复杂度 O(nlogn)O(n \log n),可过 10610^6 数据。
    • 1

    信息

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