版权声明:那个,最起码帮我加点人气吧,署个名总行吧 https://blog.csdn.net/qq_41670466/article/details/83308477
题意大致就是给你两个串,然后让你求第二个串的各个后缀在第一个串的出现次数,然后让次数乘该后缀的长度累加输出,最后结果是对1e9+7取模
思路:在讲具体思路之前,如果对扩展kmp不了解或者没听说过的话,建议先看看这个博客https://blog.csdn.net/dyx404514/article/details/41831947
回归正题:我们首先要对这个问题进行转换,因为在我所学过的算法中大都是对前缀进行处理,这样也符合串的输入顺序,所以首先需要对两个串进行反转,这样求串2的后缀就变成了串2的前缀,于是问题就转换为求转换过后的串2的各前缀在串1出现的次数和长度的乘积累加和,进一步分析就需要解决这个乘积的问题,很明显单纯的先计算出现次数然后再乘再累加一定会超时的,所以就需要对这个问题再进行转换,这里使用的方法就是计算串1的连续字串在串2的相同前缀数,如果求得串1在第1个位置开始的连续字串跟串2相同的前缀是3,那么就代表串2的前三个字符在串1出现,然后这个三就包括a,aa,aaa,(假设前三个字符是aaa),那么先计算这个三个的乘积累加,很明显是一个等差数列:1*1+1*2+1*3,如果后续又出现这几个字串,那么在加就好,反正乘积就是加法的累计。其余的细节就是扩展kmp了,在这里不在细讲,上面的连接里说的很详细
代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
int nxt[maxn];
int ex[maxn];
string s, s1;
inline long long add(long long n)
{
long long ans = ((n%mod)*((n + 1) % mod) / 2) % mod;
return ans;
}
void getnxt()
{
int len = s1.size();
int j = 0, k = 1;
nxt[0] = len;
while (j + 1 < len&&s1[j + 1] == s1[j]) j++;
nxt[1] = j;
for (int i = 2; i < len; i++)
{
int p = nxt[k] + k - 1;
int L = nxt[i - k];
if (i + L < p + 1)
nxt[i] = L;
else
{
j = max(0, p - i + 1);
while (i + j < len&&s1[i + j] == s1[j])
j++;
nxt[i] = j;
k = i;
}
}
}
void exkmp()
{
int len = s.size(), len2 = s1.size();
getnxt();
int j = 0, k = 0;
while (j < len&&j < len2&&s[j] == s1[j]) j++;
ex[0] = j;
for (int i = 1; i < len; i++)
{
int p = ex[k] + k - 1;
int L = nxt[i - k];
if (i + L < p + 1)
ex[i] = L;
else
{
j = max(0, p - i + 1);
while (i + j < len&&j < len2&&s[i + j] == s1[j]) j++;
ex[i] = j;
k = i;
}
}
}
void ini()
{
memset(nxt, 0, sizeof(nxt));
memset(ex, 0, sizeof(ex));
s.clear();
s1.clear();
}
int main()
{
ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--)
{
ini();
cin >> s >> s1;
int len = s.size();
reverse(s.begin(), s.end());
reverse(s1.begin(), s1.end());
exkmp();
long long ans = 0;
for (int i = 0; i < len; i++)
{
if (ex[i])
ans = (ans + add(ex[i]) % mod) % mod;
}
cout << ans % mod << endl;
}
//system("pause");
return 0;
}