【KMP】HDU 6153 A Secret

来源:互联网 发布:sql应用开发培训 编辑:程序博客网 时间:2024/06/03 14:20

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 1000000007int Next[N];//求next[]数组,我习惯以0为起始,-1也可以改一些东西就好了long long num[N];char s1[N], s2[N];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;}
原创粉丝点击