求一个串中不相同的子串可以用后缀数组求,这题只不过是要求子串是回文串所以也可以用后缀数组求。求不相同的子串的的算法中,对于相邻的两个后缀 i , j . 后缀 j 能产生的子串的个数为len-height [ j ]. len为 j 后缀的长度,height [ i ] 为后缀 i,j 的最长公共前缀。所以求不同子串的个数只需要扫一遍height[ ]数组即可
对于求回文串的个数,在字符串的后面接上这个字符串的逆串中间用字符串中没有出现过的字符相隔,这样以某个字符为中心的回文串就可以通过求两个后缀的最长公共前缀求得,假设i,j为以某个字符为中心的回文串的两个后缀,所以这个回文串能产生的回文串的个数为i,j的最长公共前缀,但是这里会出现重复的情况,那么如何去重呢,回想在求不相同子串的过程中的去重方法,同样可以用在这里,只不过这里不是减去height [ i ]。看下面的代码:
for(i=1;i<k-1;i++) //回文串长度为奇数的情况,偶数类似
{
num=min(num,height[i]);//num就是在这之前出现过的回文串中长度最长的和相邻两个后缀的最小值
//因为对于任意的i有lcp(suffix[i],suffix[i-1])>=lcp(suffix[i],suffix[k]) (k<i-1)
//所以这个回文串产生重复的个数就是上面的表达式
if(vis[sa[i]]==0&&vis[k-sa[i]-2]==1) //vis[]是标记以sa[i]为中间字符的两个后缀的访问时间
{
cnt=query(rank[sa[i]],rank[k-sa[i]-2]);
if(cnt<=num) continue;
ans+=cnt-num;
if(cnt>num) num=cnt;
}
else
vis[sa[i]]=1;
}
上面的代码就是去重统计。