CF1063F String Journey DP、SAM、线段树
为了方便把串反过来,条件变为ti是ti+1的真子串,答案显然不变。
一件重要的事情是必定存在一种最优解,字符串序列{t}满足|ti|=i。
考虑DP:设fi表示字符串序列{t}的最后一个串的结尾位置为i时,|t|的最大值。不难发现如果fi=x,那么一定存在最后一个串结尾位置为i、长度在[1,x]内的字符串序列。
因为有fi≤fi−1+1(因为对于一个能够满足序列长度为fi、最后一个串结尾为i的字符串序列t,把第一个字符串删掉,然后把其他的串的最后一个字符删掉,就可以得到序列长度为fi−1、最后一个串结尾为i−1的一个合法的字符串序列),所以可以从大到小枚举fi的合法取值,这里的总check次数是O(n)的。
那么问题变成如何check。考虑我们实际上只需要满足s1,i−fi中是否存在一个si−fi+1,i的子串满足该串的结尾的f值大于等于fi−1。注意到可能满足条件的只有两个子串(si−fi+1,i−1和si−fi+2,i),所以我们只需要知道这些点所有≤i−fi的endpos中的f值的最大值。注意到i−fi是单调不降的,所以我们可以使用一个指针维护当前询问的前缀,在线段树上做单点修改、子树查询最大值即可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步