HDU 6153 A Secret(KMP变形)

本文介绍如何使用KMP算法及其next数组求解一个字符串在另一个字符串中所有长度的前缀出现次数,并通过调整算法确保不会遗漏计数。提供了一段C++代码实现。

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

题意:给两个字符串S1和S2,求S2长度为i的后缀在S1中出现的次数为num[i],求所有的i*num[i]的和(模1e9+7)。

解析:此题可以利用KMP中next数组来做,求next数组不变,在KMP两个串匹配中稍作修改即可。

首先将两个串反转一下,这样就是求S2的前缀在S1中出现的次数了。

在KMP匹配中,用一个数组num来记录长度i的前缀的次数。每次匹配到长度为i的前缀时,num[i]++。

但是这样会漏掉一些计数,比如S1:abababa, S2:aba,当S2中匹配到后面的a时,即i和j都是3时,num数组只会给num[3]++,但此时S1的第二个a和S2的第一个a也匹配,但是num[1]并没有加1。

解决方法:再反响遍历一遍num数组,利用next数组,num[next[i]] += next[i],即可将遗漏的加上。

代码:

#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
typedef long long ll;
const int N = 1000005;
const ll mod = 1e9+7;
char str1[N], str2[N];
int Next[N];
int len1, len2;
ll num[N];
void GetNext(){
	int i = 0, j = -1;
	Next[0] = -1;
	while(i < len2){
		if(j == -1 || str2[i] == str2[j]){
			i++, j++;
			Next[i] = j;
		}
		else
			j = Next[j];
	}
}
void KMP(){
	GetNext();
	int i = 0, j = 0;
	while(i < len1){
		if(j == -1 || str1[i] == str2[j]){
			i++, j++;
			num[j]++;
		}
		else
			j = Next[j];
	}
}
int main(){
	std::ios::sync_with_stdio(false);
	int t;
	cin>>t;
	while(t--){
		cin>>str1>>str2;
		len1 = strlen(str1);
		len2 = strlen(str2);
		reverse(str1, str1+len1);
		reverse(str2, str2+len2);
		str2[len2++] = '#';//当S2到最后一个字符后,利用next数组自动返回到前面某个位置
		memset(num, 0, sizeof(num));
		KMP();
		ll ans = 0;
		for(int i = len2-1; i > 0; i--){
			ans = (ans + num[i] * i) % mod;
			num[Next[i]] += num[i];
		}
		cout<<ans<<endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值