题目链接
题意:给你连个字符串,s,t 求出t的所有后缀在s中出现的次数乘后缀的长度。
一开始想的后缀数组,tle,最后才知道是kmp
首先把s 和 他翻转一下,这是后就相当于求前缀了,然后求出t的next数组,然后对s跑kmp,跑的时候记录每一个长度匹配的次数,然后对于某个长度,如果他匹配了 比他小的也就匹配了,所以最后在类似求一个后缀和。
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cstring>
#define clr(x) memset(x,0,sizeof(x))
using namespace std;
#define LL long long
const LL N = 1000005;
int _next[N];
char s1[N];
char s2[N];
const LL MOD = 1e9+7;
LL cnt[N] = {0};
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
clr(_next);
clr(cnt);
scanf("%s%s",s1,s2);
int len1 = strlen(s1);
int len2 = strlen(s2);
reverse(s1,s1+len1);
reverse(s2,s2+len2);
_next[1] = -1;
_next[0] = -1;
for(int i = 1,j=-1;i<len2;i++)
{
while(j!=-1 && s2[i]!=s2[j+1])
{
j = _next[j];
}
if(s2[i]==s2[j+1])
{
j++;
}
_next[i+1] = j;
}
for(int i = 0,j=-1;i<len1;i++)
{
while(j!=-1 && s1[i]!=s2[j+1])
{
j = _next[j];
}
if(s1[i]==s2[j+1])
j++;
if(j!=-1)
cnt[j+1]++;
if(j==len2-1)
{
j = _next[j+1];
}
}
for(int i = len1;i>0;i--)
{
if(_next[i]!=-1)
{
cnt[_next[i]+1] += cnt[i];
}
}
//cout << cnt[2] << endl;
LL ans = 0;
for(int i = 1;i<=len1;i++)
{
ans += cnt[i]*i;
ans%=MOD;
}
printf("%lld\n",ans);
}
return 0;
}