[NOI2016十连测]string

137 篇文章 1 订阅
38 篇文章 0 订阅

题目

我并没有在 O J OJ OJ 上找到原题。所以贴图片吧(老师的 PPT \text{PPT} PPT 中的)。

在这里插入图片描述
数据范围与约定
强制在线。操作数不超过 2 × 1 0 5 2\times 10^5 2×105 ,字符集大小不超过 1 0 5 10^5 105

思路

简化题意:有一棵 trie \text{trie} trie 树,每次新增一个叶子,求最长 border \text{border} border (众所周知,最长 border \text{border} border 长度与最短循环节长度相加,得到原字符串长度)。

最长 border \text{border} border 不就是 K M P KMP KMP 的失配指针吗?而且总复杂度是 O ( n ) \mathcal O(n) O(n) 的?

然而, K M P KMP KMP 的复杂度是均摊的。对于新加入的叶子,它可能需要计算 O ( n ) \mathcal O(n) O(n) 次(假如它的祖先都是一步到位)。

这里我们就要使用奇技淫巧了(甚至,可以用于普通的 K M P KMP KMP 来优化一丢丢)。

对跳失配指针的过程进行优化。不妨记 f ( x ) f(x) f(x) 为失配函数。将 t r i e trie trie 上面的那一条链抽象出来,得到一个字符串。也就是说,幻想我们在进行 K M P KMP KMP 匹配。

  • 如果 f ( x ) ≤ ⌊ x 2 ⌋ f(x)\le\lfloor\frac{x}{2}\rfloor f(x)2x ,该干啥干啥,跳过去就是了。
  • 否则,存在一个循环节 x − f ( x ) x-f(x) xf(x) 。假如 f ( x ) f(x) f(x) 的后一位仍然不能匹配,那么可以直接跳到第一个循环节中的对应位置。也就是 ( x − 1 )   m o d   [ x − f ( x ) ] + 1 (x-1)\bmod[x-f(x)]+1 (x1)mod[xf(x)]+1

每次至少要跳没 x 2 \frac{x}{2} 2x 个字符,所以复杂度变成了 O ( log ⁡ n ) \mathcal O(\log n) O(logn)

回到 trie \text{trie} trie 上,我们怎么解决“得到第 ( x − 1 )   m o d   [ x − f ( x ) ] + 1 (x-1)\bmod[x-f(x)]+1 (x1)mod[xf(x)]+1 级祖先”?

很简单,树上倍增。新插入叶子时,再次计算即可。仍然是 O ( log ⁡ n ) \mathcal O(\log n) O(logn) 的复杂度。

思路二

定义 g ( x , c ) g(x,c) g(x,c) 为,匹配到 x x x ,下一个字符是 c c c ,何去何从。

显然,递推方法是

  • x x x 有字符 c c c 作为子节点时,有 g ( x , c ) = s o n ( x , c ) g(x,c)=son(x,c) g(x,c)=son(x,c)
  • 否则,有 g ( x , c ) = g [ f ( x ) , c ] g(x,c)=g[f(x),c] g(x,c)=g[f(x),c] f ( x ) f(x) f(x) 同上,为失配函数)。

那么,新加入的叶子节点,其 g g g 函数该如何求解?只会使用第二条规则。

现在有一个问题, f ( x ) f(x) f(x) 怎么算?答案是 f ( x ) = g [ f a ( x ) , c ] f(x)=g[fa(x),c] f(x)=g[fa(x),c] ,其中 c c c x x x 相较于 f a ( x ) fa(x) fa(x) 新增的末尾字符。注:此处的 g [ f a ( x ) , c ] g[fa(x),c] g[fa(x),c] 尚未赋值为 x x x ,尽管马上我们就要这么做。

于是,我们用 可持久化线段树 维护 g g g 函数。分三步进行。

  1. f a ( x ) fa(x) fa(x) 的线段树中找到 f ( x ) f(x) f(x)
  2. f ( x ) f(x) f(x) 的线段树拷贝过来。
  3. 最后将 g [ f a ( x ) , c ] g[fa(x),c] g[fa(x),c] 赋值为 x x x

代码

此题重在思想,而非代码,对吗?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值