码迷,mamicode.com
首页 > 其他好文 > 详细

hdu6153 扩展kmp求一个字符串的后缀在另一个字符串出现的次数。

时间:2017-08-21 12:37:24      阅读:173      评论:0      收藏:0      [点我收藏+]

标签:acm   表示   show   ext   xtend   air   line   题目   amp   

/**
题目:hdu6153
链接:http://acm.hdu.edu.cn/showproblem.php?pid=6153
题意:给定两个串,求其中一个串t的每个后缀在另一个串s中出现的次数乘以其长度之和。
思路:扩展kmp
先将两个字符串翻转过来。那么变成求t串每个前缀在s串出现的次数。
直接扩展kmp求出extend[i]表示s串[i,n-1]子串和t串的最长公共前缀。
那么s串从i开始和t串前缀有匹配的贡献为1+2+...+extend[i] = extend[i]*(extend[i]+1)/2;

*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <iostream>
#include <cmath>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
#define ms(x,y) memset(x,y,sizeof x)
typedef pair<int, int> P;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 1e6+100;
char s[maxn], t[maxn];
int Next[maxn], extend[maxn];
int cnt[maxn];
LL ans;
void GetNext(char *T,int* next)
{
    int a=0;
    int Tlen=strlen(T);
    next[0]=Tlen;
    while(a<Tlen-1&&T[a]==T[a+1]) a++;
    next[1]=a;
    a=1;
    for(int k=2;k<Tlen;k++)
    {
        int p=a+next[a]-1,L=next[k-a];
        if((k-1)+L>=p)
        {
            int j=(p-k+1)>0? p-k+1:0;
            while(k+j<Tlen&&T[k+j]==T[j]) j++;
            next[k]=j;
            a=k;
        }
        else next[k]=L;
    }
}

void GetExtend(char *S,char *T,int* next,int* extend)
{
    int a=0;
    GetNext(T,next);
    int Slen=strlen(S);
    int Tlen=strlen(T);
    int MinLen=Slen<Tlen? Slen:Tlen;
    while(a<MinLen&&S[a]==T[a]) a++;
    extend[0]=a;
    a=0;
    for(int k=1;k<Slen;k++)
    {
        int p=a+extend[a]-1,L=next[k-a];
        if((k-1)+L>=p)
        {
            int j=(p-k+1)>0? p-k+1:0;
            while(k+j<Slen&&j<Tlen&&S[k+j]==T[j]) j++;
            extend[k]=j;
            a=k;
        }
        else extend[k]=L;
    }
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%s%s",s,t);
        ms(cnt,0);
        int n = strlen(s);
        int m = strlen(t);
        reverse(s,s+n);
        reverse(t,t+m);
        GetExtend(s,t,Next,extend);
        ans = 0;
        for(int i = 0; i < n; i++){
            ans = (ans+(LL)extend[i]*(extend[i]+1)/2)%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

hdu6153 扩展kmp求一个字符串的后缀在另一个字符串出现的次数。

标签:acm   表示   show   ext   xtend   air   line   题目   amp   

原文地址:http://www.cnblogs.com/xiaochaoqun/p/7403509.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!