【APIO2014】Palindromes
先说一下自己的SAM做法:
看到回文串我们首先考虑对以下字符串建立SAM:正串+特殊字符1+特殊字符2+反串。这样也许能有一点用。晚上睡觉前我考虑的是对于正串的endpos在反串中也是一样的endpos,这样只需要找到他们在parent tree的LCA就可以确定LCA的祖先是一个回文串了,因此可以O(nlogn)的计算答案。
但是早上突然想到假了,因为正串的endpos在反串中体现为所谓的beginpos,而我们有的只是endpos,反串对应的endpos其实是正串的beginpos,而两者我们没办法搞定,这个做法告一段落(?)
但事实上我们也不是不能优化,我们发现对于回文中心,他会在正串中做endpos,也会在反串中做endpos并且两串加起来还一定是一个回文的字符串,符合我们的预想,所以我们可以枚举中间点,然后O(nlogn)求解,需要注意的是回文串题目一般都需要分奇偶来讨论这题也不例外,因为偶串的回文中心是中间两个之间的部分,而奇串就是中间那个字符。而对应点在parent tree上的LCA以及他的祖先都可以保证原串中按回文中心展开一定是一个回文串,至此SAM做法做完。
但是你算一下空间就会发现有点卡空间,实现时候要小心一点,最后我用了235MB过的。
然后又有一种很厉害,很简短的构建自动机的fail失配树的方法:
我们考虑构建一个自动机,转移边表示当前节点两端同时加上一个字符会到哪个节点。而再建一个fail节点表示如果最后一个字符失配了他的最长严格后缀回文串是哪个节点,还有len表示这个节点的字符串长度。初始化的时候由于回文串,所以奇串和偶串处理边界不太一样,偶串我们需要有一个len=0的节点,保证s[i-1]和s[i]匹配。而奇串边界只有一个串的时候是s[i]和s[i]相当于是len=-1了,而如果偶串边界不成功还要向len=-1连边保证不会死循环,所以fail[0]=1。
正式考虑转移:如果当前加入的字符和目前回文串不匹配(x-len[x]-1和x不相等,即不构成回文串),则不断跳fail直至匹配。然后更新转移nxt[x][ch]以及它所对应的fail,fail[nxt[x][ch]]=nxt[getfail(fail[x])][ch](注意fail定义的严格)。然后再用cnt记录每个点经过多少次,由于我们是建了一颗失配树,所以可以用树形dp的方法统计子树sum然后再乘len取max即可。
Submission:
SAM:https://uoj.ac/submission/609889
另一种自动机:https://uoj.ac/submission/226409

浙公网安备 33010602011771号