思路:通过学习后缀数组知识了解,第i大的后缀和第j大的后缀的lcp等于它们之间,所有相邻对的lcp的最小值。然后题意是最多可以skip3个不同的点,求 s s s中有多少子串和 s 0 s_0 s0匹配。
const int N = 2e5+5, M = 21; char s[N],s0[N]; int sa[N], t[N << 1], t2[N << 1], c[N], height[N], rk[N]; int n, m; void get_sa() { //s从1开始,排名从1开始 int i, *x = t, *y = t2, m = 256; for (i = 1;i <= m;i++)c[i] = 0; for (i = 1;i <= n;i++)c[x[i] = s[i]]++; for (int i = 2;i <= m;i++)c[i] += c[i - 1]; for (i = n;i;i--)sa[c[x[i]]--] = i; for (int k = 1;k <= n;k <<= 1) { int num = 0; for (i = n - k + 1;i <= n;i++)y[++num] = i; for (i = 1;i <= n;i++)if (sa[i] > k)y[++num] = sa[i] - k; for (i = 1;i <= m;i++)c[i] = 0; for (i = 1;i <= n;i++)c[x[i]]++; for (i = 2;i <= m;i++)c[i] += c[i - 1]; for (i = n;i;i--)sa[c[x[y[i]]]--] = y[i]; swap(x, y); x[sa[1]] = 1;num = 1; for (int i = 2;i <= n;i++) x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++num; if (num == n)break; m = num; } } void get_height() { int k = 0; for (int i = 1;i <= n;i++)rk[sa[i]] = i; for (int i = 1;i <= n;i++) { if (rk[i] == 1)continue; if (k)k--; int j = sa[rk[i] - 1]; while (j + k <= n && i + k <= n && s[i + k] == s[j + k])k++; height[rk[i]] = k; } } int rmq[N][M + 2], Lg2[N]; void get_st() { for (int i = 1;i <= n;i++) rmq[i][0] = height[i]; for (int i = 2;i <= n;i++) Lg2[i] = Lg2[i >> 1] + 1; for (int k = 1;(1 << k) <= n;k++) for (int i = 1;i + (1 << k) - 1 <= n;i++) rmq[i][k] = min(rmq[i][k - 1], rmq[i + (1 << k - 1)][k - 1]); } int lcp(int x, int y) { int i = rk[x], j = rk[y]; if (i > j) swap(i, j); int t = Lg2[j - i]; return min(rmq[i + 1][t], rmq[j - (1 << t) + 1][t]); } int main() { //freopen("in.txt", "r", stdin); int t;t = in(); while (t--) { scanf("%s%s", s + 1, s0 + 1); int lens = strlen(s + 1), lens0 = strlen(s0 + 1); n = lens + lens0;//两个串接起来,后序求lcp f(i, 1, lens0)s[i+lens] = s0[i]; get_sa(); get_height(); get_st(); int re = lens - lens0; if (re < 0) { puts("0");continue; } int ans = 0; f(i, 1, 1 + re) { int num = 0; int len = 0;//lcp长度 while (num <=3 && len <= lens0) { int nowlcp = lcp(i+len, lens + 1 + len); len += nowlcp+(num<3); num++; } if (len >=lens0)ans++; } cout << ans << endl; } return 0; }