hdu6153
hdu6153
题意
给出两个字符串,询问第二个字符串的所有后缀串在第一个字符串中的出现次数。
分析
将两个字符串逆序存储,将第二个字符串作为模板串,对第一个串进行 \(KMP\) ,开一个数组 \(cnt\) 记录模板串每一个前缀串的个数,最后用 \(fail\) 数组去更新下 \(cnt\) 数组。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD = 1e9 + 7;
const int MAXN = 1e6 + 10;
char s1[MAXN], s2[MAXN];
int fail[MAXN];
int cnt[MAXN];
void getFail(char T[]) {
memset(fail, 0, sizeof fail);
int len = strlen(T);
fail[0] = -1;
int i = 0, j = -1;
while(i < len) {
if(j == -1 || T[i] == T[j]) {
i++; j++;
fail[i] = j;
} else {
j = fail[j];
}
}
}
ll solve(char S[], char T[]) {
memset(cnt, 0, sizeof cnt);
getFail(T);
int i = 0, j = 0;
int len = strlen(S);
while(i < len) {
if(j == -1 || S[i] == T[j]) {
i++; j++;
cnt[j]++;
} else {
j = fail[j];
}
}
ll ans = 0;
int len2 = strlen(T);
for(int i = len2; i > 0; i--) {
cnt[fail[i]] += cnt[i];
}
for(int i = 1; i <= len2; i++) {
ans = (ans + 1LL * cnt[i] * i) % MOD;
}
return ans;
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
scanf("%s%s", s1, s2);
int l1 = strlen(s1), l2 = strlen(s2);
reverse(s1, s1 + l1);
reverse(s2, s2 + l2);
printf("%lld\n", solve(s1, s2));
}
return 0;
}