【KMP计数】 A Secret

题目出处:A Secret

A Secret

    Today is the birthday of SF,so VS gives two strings S1,S2 to SF as a present,which have a big secret.SF is interested in this secret and ask VS how to get it.There are the things that VS tell:
    Suffix(S2,i) = S2[i...len].Ni is the times that Suffix(S2,i) occurs in S1 and Li is the length of Suffix(S2,i).Then the secret is the sum of the product of Ni and Li.
    Now SF wants you to help him find the secret.The answer may be very large, so the answer should mod 1000000007.
Input:
Input contains multiple cases.
    The first line contains an integer T,the number of cases.Then following T cases.
    Each test case contains two lines.The first line contains a string S1.The second line contains a string S2.1<=T<=10.1<=|S1|,|S2|<=1e6.S1 and S2 only consist of lowercase ,uppercase letter.
Output
For each test case,output a single line containing a integer,the answer of test case.
The answer may be very large, so the answer should mod 1e9+7.
Sample Input
2
aaaaa
aa
abababab
aba
Sample Output
13
19

题目大意:


    给定n个测试样例,每个测试样例,有两个字符串,s1,s2,先求出s2的每个后缀子串出现在s1的个数,再用s2每个后缀子串长度,最后相乘求和。

题目分析:


题目要求,模式串s的各个后缀出现次数乘以其长度的和。
1. 先求出模式串s的个后缀出现次数
2. 计算对应前缀次数乘以长度和

解题思路:


      很明显这是一道字符串匹配处理题目,所以使用KMP算法进行求解。

KMP算法,可以用于字符串的匹配,设文本串为t,模式串为s,文本串长度为lent,模式串长度为lens,KMP算法可以判断文本串t是否存在模式串是s。


      首先想到的是暴力求解,先设字符串temp,temp是s[0-i]的部分,也看是s的前缀部分,遍历所有前缀部分进行KMP匹配计数,然后计数对应答案,结果是超时的,所以要进行一定优化。
      首先要KMP知道是可以求出,模式串s出现在文本串t的次数,所以可以求出模式串s的出现次数,又因为s的出现,伴随着s[0],s[0..1] ,s[0..i]的出现,意味着算出s的次数是可以通过递推算出其它的次数。
    但题目要的是后缀,这时候只需要反转t,s即可,问题就转化为了求出模式串s的前缀出现次数。

创建一个数组cnt[i],记录s[0…i]出现的次数,cnt[0],表示s[0]出现的次数,cnt[1],表示s[0…1]出现的次数,以此类推。


      计数可以在KMP中同步进行,在每次单个字母模式串s下标j匹配成功的时候,cnt[j]=cnt[j]+1,因为在该下标匹配成功意味着出现了s[0...j],所以cnt[j]递增。

Next数组是KMP算法的产物,Next[j]表示的是模式串s的 前缀子串s[0…k]和后缀子串s[j-k…j] 的最大下标k 。


    在进行完了KMP操作后,此时的cnt数组并未完成统计完成,因为KMP中的回退操作 (j=Next[j])会导致一部分的出现的前缀字符串统计次数丢失,比如 t = abababab,s = aba, 进行了KMP操作后,cnt={1,3,3} ,因为aba在进行匹配的 当j=2的时候Next[j]=0,也就下一个匹配的字母为‘b’,即统计了s[0..1],从而缺少了对s[0]的统计。 所以只要从cnt[lens-1]递推求和即可。
for(int i=len-1;i>=0;--i)                     
 	cnt[Next[i]]+=cnt[i];
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值