您的位置:首页 > 其它

【KMP】HDU 6153 A Secret

2017-08-21 09:16 393 查看
Problem Description

给你T组测试数据,每组测试数据,给你两个串,一个母串一个子串,让你求子串的所有后缀串,对于每个后缀串都和母串匹配,求出匹配次数,匹配次数*后缀串长度 求和 % 1000000007就是结果。

Sample Input

2

aaaaa

aa

abababab

aba

Sample Output

13

19

Hint

case 2:

Suffix(S2,1) = “aba”,

Suffix(S2,2) = “ba”,

Suffix(S2,3) = “a”.

N1 = 3,

N2 = 3,

N3 = 4.

L1 = 3,

L2 = 2,

L3 = 1.

ans = (3*3+3*2+4*1)%1000000007.

思路:

匹配问题,字符串很长,暴力是肯定过不了,所以转眼就去思考KMP。如果只是单单匹配一个后缀串,在主串出现的次数,这个还是很好解决的。所以思考点就是所有的后缀串在主串出现的次数,如何解决的问题。然后认真思考一下,就拿case2来说,如果aba匹配成功,那么是不是就代表ba匹配成功,a匹配成功。可这时aba匹配一次,ba匹配一次,a匹配了两次。该如何解决这个问题,防止重复计算,或者少计算。就是发现主串和子串都反转过来。这样匹配主串匹配到的子串也能匹配到,这样就很好的解决了上述问题,可是如果单单这样a只匹配了一次。aba的next[]数组是0,0,1。num[next[2] - 1] += num[2],这样我们就可以解决少计算的问题。详细还是得看代码。看了代码应该就理解为何这样做了。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1000055
#define mod 1000000007
int Next
;//求next[]数组,我习惯以0为起始,-1也可以改一些东西就好了
long long num
;
char s1
, s2
;
void get_next(char s2[])//求next[]数组,不会的最好先去学习。对next[]数组用法要理解深点。
{
int i, j = 0, len = strlen(s2);
Next[j] = 0;
for(i = 1; i < len; i++)
{
j = Next[i - 1];
while(j && s2[j] != s2[i])
j = Next[j - 1];
if(s2[j] == s2[i]) Next[i] = ++j;
else Next[i] = 0;
}
}
void KMP(char s1[], char s2[])//主串和最大后缀子串匹配
{
int i = 0, j = 0, len1 = strlen(s1), len2 = strlen(s2);
while(i < len1)
{
if(s1[i] == s2[j])//相等
{
num[j]++;i++; j++;//num[j]++,记录匹配成功几次
}
else
{
if(j == 0) i++;
else j = Next[j - 1];
}
if(j >= len2)
{
/*printf("%d\n", next[j - 1]);*/
j = Next[j - 1];//最大后缀子串匹配完了。j下标跳到(这
//个不知道怎么表达出来)和s2[j-1]一样字母的后面(这个后
//面不是简简单单的后面,自己画出来理解把)。
//从这里就可以看出num[next[2] - 1] += num[2]为什么这个式子了。
}
}
}
int main()
{
int T, i, len1, len2;
scanf("%d", &T);
while(T--)
{
scanf("%s %s", s1, s2);
len1 = strlen(s1), len2 = strlen(s2);
for(i = 0; i < len1 / 2; i++)//反转
swap(s1[i], s1[len1 - i - 1]);
for(i = 0; i < len2 / 2; i++)
swap(s2[i], s2[len2 - i - 1]);
memset(num, 0, sizeof(num));
get_next(s2); KMP(s1, s2);
long long ans = 0;
for(i = len2 - 1; i >= 0; i--)
{
ans = (ans + num[i] * (i + 1) % mod) % mod;
num[Next[i] - 1] += num[i];//累加
}
printf("%lld\n", ans);//输出
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: