1 条题解

  • 0
    @ 2025-12-11 7:28:25

    题解:动态维护子串的 bessie 匹配数

    问题转化

    定义 B(s)B(s) 为从字符串 ss 中删除若干字符后能得到的形如 bessie 重复串中 bessie 的最大出现次数。

    A(t)=t的所有子串 sB(s)A(t) = \sum_{t的所有子串\ s} B(s)

    支持单点修改 tt 的字符,每次询问修改后的 A(t)A(t)

    t,U2×105|t|, U \le 2\times 10^5

    关键观察

    B(s)B(s) 等价于按顺序匹配 bessie 这个单词能匹配多少次。

    设模式串 P="bessie"P = \text{"bessie"},长度 L=6L=6

    B(s)B(s) 就是 ss 作为序列,能完整匹配 PP 的最大次数,允许跳过字符。

    自动机模型

    建立自动机:状态 00 表示未开始匹配,状态 i(1i6)i(1\le i\le 6) 表示已匹配到 bessie 的第 ii 个字符。状态 66 匹配完一个 bessie 后回到状态 00(因为可以连续匹配)。

    实际上:匹配完一次 bessie 后,最后一个 e 同时也是下一个 bessieb 的前一个字符,所以状态转移是:

    • 在状态 ii,若下一个字符等于 P[i+1]P[i+1](下标从 1 开始),则转移到状态 i+1i+1(若 i=6i=6 则转移到状态 11 并计数 +1)。
    • 否则停留在状态 ii(跳过字符)。

    但为了统计 B(s)B(s) 的值,我们需要知道在扫描 ss 时能完成多少次完整匹配。

    动态规划计算 B(s)B(s)

    dp[i]dp[i] 表示扫描到当前位置时,已经匹配了 iibessie 的字符(0i50\le i\le 5i=5i=5 时再遇到 e 就完成一次)。
    但为了计算 B(s)B(s),我们需要知道最大匹配次数,这等价于贪心匹配:尽可能早地完成每一次 bessie

    所以 B(s)B(s) 就是从左到右贪心匹配 bessie 能得到的次数。

    计算所有子串的 B(s)B(s)

    考虑每个子串 t[l..r]t[l..r],它的 BB 值就是从左到右扫描该子串能匹配到的 bessie 个数。

    固定左端点 ll,当右端点 rr 右移时,B(t[l..r])B(t[l..r]) 可能增加(当完成一次 bessie 匹配时)。

    定义 next[l]next[l] 为从位置 ll 开始贪心匹配一个 bessie 结束的位置的下一个位置(即匹配完一次 bessie 后的下一个位置)。若无法匹配则 next[l]=next[l] = \infty

    B(t[l..r])B(t[l..r]) 等于从 ll 开始,不断跳 nextnext 直到超过 rr 的跳跃次数。

    转化为计数问题

    $A(t) = \sum_{l\le r} B(t[l..r]) = \sum_{l} \sum_{r\ge l} B(t[l..r])$。

    固定 ll,考虑右端点 rrllnn 移动,B(t[l..r])B(t[l..r]) 是一个分段常数函数,每当 rr 经过一个 nextnext 跳跃点时增加 11

    设从 ll 开始能匹配到 kkbessie,第 iibessie 的结束位置为 eie_i(即跳 iinextnext 后的位置的前一个位置),则:

    • 对于 r<e1r < e_1B=0B=0
    • 对于 e1r<e2e_1 \le r < e_2B=1B=1
    • ...
    • 对于 ek1r<eke_{k-1} \le r < e_kB=k1B=k-1
    • 对于 rekr \ge e_kB=kB=k

    所以固定 ll 的贡献为:

    i=1ki×(ei+1ei)\sum_{i=1}^{k} i \times (e_{i+1} - e_i)

    其中 ek+1=n+1e_{k+1}=n+1

    计算总贡献

    $A(t) = \sum_{l=1}^n \sum_{i=1}^{k_l} i \times (e_{l,i+1} - e_{l,i})$。

    交换求和顺序:

    $$A(t) = \sum_{i\ge 1} i \times \sum_{l} (e_{l,i+1} - e_{l,i}) $$

    其中 el,ie_{l,i} 是从 ll 开始第 iibessie 的结束位置。

    高效维护

    考虑每个 bessie 的出现对答案的贡献。

    若一个 bessie 覆盖区间 [a,b][a,b](从位置 aab 开始到位置 bbe 结束),则它对哪些子串 t[l..r]t[l..r]BB 值有贡献?

    lal \le arbr \ge b 时,这个 bessie 会被统计在 B(t[l..r])B(t[l..r]) 中。但还要考虑在 [l,r][l,r] 内它是第几个 bessie

    更简单的想法:考虑每个 bessie 的出现,它作为第 jjbessie 对答案贡献为 j×j \times 包含它作为第 jjbessie 的子串个数。

    自动机 + 数据结构

    建立 bessie 的自动机,状态 0..50..5 表示已匹配的字符数。

    扫描字符串,维护每个位置 ii 的自动机状态 st[i]st[i]

    对于每个位置 ii,若 t[i]t[i] 使自动机从状态 55(已匹配 bessi)转移到状态 00(完成一个 bessie),则说明 ii 是一个 bessie 的结束位置。

    设这个 bessie 的开始位置为 startstart,则从任意 lstartl \le startrir \ge i 的子串都会包含这个完整的 bessie

    B(t[l..r])B(t[l..r]) 中这个 bessie 是第几个?这取决于在 [l,start1][l,start-1] 中已完成了多少个 bessie

    最终算法

    1. 预处理 bessie 的自动机。
    2. 扫描字符串,记录每个 bessie 出现的开始位置 LL 和结束位置 RR
    3. 维护一个数组 cnt[x]cnt[x] 表示当前位置作为左端点时,已经完成了 xxbessie 的左端点个数。
    4. 从左到右扫描右端点 rr
      • rr 是一个 bessie 的结束位置,则它对答案的贡献为 x0(x+1)×cnt[x]\sum_{x\ge 0} (x+1) \times cnt[x](因为它作为第 x+1x+1bessie 被统计)。
      • 然后更新 cntcnt:所有 lLl \le L 的左端点完成数 +1+1,即 cnt[x]cnt[x] 转移到 cnt[x+1]cnt[x+1]
    5. 用线段树或 Fenwick 树维护 cntcnt 数组的区间和与区间平移操作。

    单点修改时,重新计算受影响区间的 bessie 出现情况,更新数据结构。

    复杂度

    • 预处理 O(n)O(n)
    • 每次修改影响 O(L)O(L)bessieL=6L=6),更新 O(logn)O(\log n)
    • 总复杂度 O((n+U)logn)O((n+U)\log n)
    • 1

    信息

    ID
    6081
    时间
    4000ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者