扩展kmp

来源:互联网 发布:怎么盗用淘宝视频 编辑:程序博客网 时间:2024/05/22 08:07

给出两个字符串s1,s2,求出s2的每一个后缀在s1中出现的次数乘以这个后缀的长度,并累加求和,输出这个和

//next[i]表示pat与pat[i,len-1]的最长公共前缀//extend[i]表示pat与ori[i,len-1]的最长公共前缀typedef long long ll;const int N = 1000000 + 10, mod = 1e9 + 7;char ori[N], pat[N];int Next[N], extend[N];int num[N];int cas = 0;void get_next(char *pat){    int len = strlen(pat);    Next[0] = len;    int k = 0;    while(k + 1 < len && pat[k] == pat[k+1]) ++k;    Next[1] = k;    k = 1;    for(int i = 2; pat[i]; i++)    {        if(i + Next[i-k] < k + Next[k]) Next[i] = Next[i-k];        else        {            int j = max(k + Next[k] - i, 0);            while(i + j < len && pat[j] == pat[i+j]) ++j;            Next[i] = j;            k = i;        }    }}void extkmp(char *ori, char *pat){    get_next(pat);    int leno = strlen(ori), lenp = strlen(pat);    int k = 0;    while(k < leno && k < lenp && ori[k] == pat[k]) ++k;    extend[0] = k;    k = 0;    for(int i = 1; ori[i]; i++)    {        if(i + Next[i-k] < k + extend[k]) extend[i] = Next[i-k];        else        {            int j = max(k + extend[k] - i, 0);            while(i + j < leno && j < lenp && ori[i+j] == pat[j]) ++j;            extend[i] = j;            k = i;        }    }}int main(){    int t;    scanf("%d", &t);    while(t--)    {        scanf("%s%s", ori, pat);        int leno = strlen(ori), lenp = strlen(pat);        reverse(ori, ori + leno);        reverse(pat, pat + lenp);        extkmp(ori, pat);        memset(num, 0, sizeof num);        for(int i = 0; i < leno; i++) num[extend[i]]++;        ll ans = 0;        for(int i = lenp; i >= 1; i--)        {            num[i] += num[i+1];            ans = (ans + 1LL * num[i] * i) % mod;        }        printf("%lld\n", ans);    }    return 0;}
原创粉丝点击