hdu 3948 求不同回文串的个数

本文介绍如何利用后缀数组高效求解字符串中的不同回文串数量。通过对字符串及其逆串进行处理,并借助后缀数组及最长公共前缀概念,实现对回文串的有效计数,同时解决重复统计的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

求一个串中不相同的子串可以用后缀数组求,这题只不过是要求子串是回文串所以也可以用后缀数组求。求不相同的子串的的算法中,对于相邻的两个后缀 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;
}


上面的代码就是去重统计。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值