先不考虑复杂度,考虑一段子串
[
i
,
j
]
[i,j]
[i,j]对应的答案。尽量将问题往
S
A
M
SAM
SAM上去靠,发现子串
[
i
,
j
]
[i,j]
[i,j]对应的就是从
t
0
t_0
t0出发的一条链。假设转移过去的子串是
[
i
′
,
j
′
]
[i',j']
[i′,j′],如果
j
′
=
j
j'=j
j′=j那么转移到的点一定是后缀树上的祖先节点,总之这个转移可以提前预处理出来。如果
j
′
≠
j
j'\ne j
j′=j那么相当于就是在链上取
max
\max
max。又因为
S
A
M
SAM
SAM的节点个数是线性的所以直接
D
P
DP
DP,这道题就做完了。
这是我做这道题的第一想法,但是其实我们可以再冷静的分析一步。先不考虑交叉的情况,简单画一个图可以发现最优方案中
s
i
−
1
s_{i-1}
si−1一定是
s
i
s_i
si的后缀。这样我们就不用管建出来的
D
A
G
DAG
DAG,只需要考虑后缀树上的情形了,因为后缀树对应后缀链接。
比较让人纠结的地方在于,同一等价类对应的答案相同吗?这就涉及到我们对
S
A
M
SAM
SAM基本性质的了解了。抛出一个结论:设
s
s
s是节点
u
u
u对应的最长串,
v
v
v是
u
u
u的祖先,那么
v
v
v对应的所有字符串在
s
s
s中的匹配情况相同。证明的关键在于利用
endpos
\text{endpos}
endpos集合相同。感觉这个证明脑补一下应该不难就略过了。这也说明了一件事,对后缀性质的充分理解才是解决问题的关键。
最后是关于实现。直接暴力二分的复杂度是
O
(
n
log
2
n
)
O(n\log^2 n)
O(nlog2n)。但是因为是在树上所以能做的操作还是比较多的,比如说这道题就可以根据父亲的信息来计算,注意到一条链上的
D
P
DP
DP值是连续的,并且相邻两个位置的
D
P
DP
DP值不超过
1
1
1,因此可以做到线性。这个地方的处理还是比较巧妙的。复杂度
O
(
n
log
n
)
O(n\log n)
O(nlogn)。
就是模板有点长。
打了一发代码,感觉最恶心的地方还是在于在
S
A
M
SAM
SAM上维护一些比较繁琐的信息。如果对
S
A
M
SAM
SAM不熟悉的话还是很容易搞错的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
2022-06-30 【学习笔记】简单dp