「考试总结」2021-01-25 口胡

T1

首先有"本质不同的回文串的数量级是 (O(n)) 的"

证明很简单,考虑sam上最多有 (2n-1) 个节点,同时这些节点中每个最多有一个回文串

(如果有多个的话,那么短串的 (endpos) 比长串要多)

其实在这个题目里面关注的是 (midpos),那么给所有的回文串标号

(manacher) 处理所有的回文中心,把短串向长串连边得到一个树

对于每次处理的 (id[i-r[i]+1,i+r[i]-1]) 异或上 (i) 最后按照 (SAM) 维护 (endpos) 个数那样维护 (midpos) 的异或和即可

一开始想的是倍增后缀树的做法,其实和正解是一致的,考完了之后优化了一下思路写了出来

所以以后要注意的是难题口胡完了要写

复杂度 (Theta(n))

注意的几个点:

(1.) 手写 (hash)

(2.) 字符串清空一定要手动清全,因为 (t[i]) 后面的遗留可能对计算造成影响

(3.) 森林的根节点的 (res[x]) 不能取最大值

T2

子串排名递减,总和增加,所以两者交点最多有一个,二分统计即可

但是考试的时候不会如何求排名,所以 (SAM) 维护子串排名方式如下:

每个后缀树上的点维护的是一个后缀,那么我们翻转之后就能得到前缀

先算 (endpos) 大小表示这个点一共多少个串

然后把所有的出边都标号,标号就是 (s[pos[x]+len[fa[x]]])

这样每个点在后缀树上排序之后再 (dfs) 得到每个点的 (rk)

对于每个 ([l,r]) 倍增出来对应的点之后直接 (rk[now]+len[now]-(r-l+1)+1) 即可

T3

后缀自动机板子题,不过考试的过程中发现 (dfs) 会本地爆栈,浪费了很多时间回忆如何写基数排序,如下:

for(reg int i=1;i<=tot;++i) ton[len[i]]++; 
        for(reg int i=1;i<=slen;++i) ton[i]+=ton[i-1]; 
        for(reg int i=tot;i>=1;--i) id[ton[len[i]]--]=i;
        for(reg int i=tot;i>=1;--i){
            if(sz[id[i]]>1) ans=max(ans,1ll*sz[id[i]]*len[id[i]]); 
            sz[fa[id[i]]]+=sz[id[i]];
        } printf("%lld
",ans);

端正态度,加速思考

原文地址:https://www.cnblogs.com/yspm/p/14324423.html