题意
给出两个字符串,询问第二个字符串的所有后缀串在第一个字符串中的出现次数。
分析
将两个字符串逆序存储,将第二个字符串作为模板串,对第一个串进行 \(KMP\) ,开一个数组 \(cnt\) 记录模板串每一个前缀串的个数,最后用 \(fail\) 数组去更新下 \(cnt\) 数组。
code
#includeusing 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;}