[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=4566
[算法]
首先 , 子串是后缀的前缀
考虑拼接两个字符串 , 中间用不可见字符隔开 , 求出该字符串的后缀数组
那么前缀相同的后缀一定排名一定接近
而我们又知道lcp(i , j) = min{ height[rk[i] + 1] , height[rk[i] + 2] ... , height[rk[j]] }
维护一个单调递增的后缀数组即可
时间复杂度 : O(NlogN)(N = |A| + |B|)
[代码]
#include<bits/stdc++.h> using namespace std; #define N 400010 const int ALPHA = 26; typedef long long ll; typedef long double ld; typedef unsigned long long ull; struct info { int height; int cnta , cntb; } ; int n , m , len; int height[N] , rk[N] , sa[N]; char s[N] , s1[N] , s2[N]; template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); } template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline void build_sa() { static int x[N] , y[N] , cnt[N]; memset(cnt , 0 , sizeof(cnt)); for (int i = 1; i <= len; i++) ++cnt[(int)s[i]]; for (int i = 1; i <= 256; i++) cnt[i] += cnt[i - 1]; for (int i = 1; i <= len; i++) sa[cnt[s[i]]--] = i; rk[sa[1]] = 1; for (int i = 2; i <= len; i++) rk[sa[i]] = rk[sa[i - 1]] + (s[sa[i]] != s[sa[i - 1]]); for (int k = 1; rk[sa[len]] != len; k <<= 1) { for (int i = 1; i <= len; i++) x[i] = rk[i] , y[i] = (i + k <= len) ? rk[i + k] : 0; memset(cnt , 0 , sizeof(cnt)); for (int i = 1; i <= len; i++) ++cnt[y[i]]; for (int i = 1; i <= len; i++) cnt[i] += cnt[i - 1]; for (int i = len; i >= 1; i--) rk[cnt[y[i]]--] = i; memset(cnt , 0 , sizeof(cnt)); for (int i = 1; i <= len; i++) ++cnt[x[i]]; for (int i = 1; i <= len; i++) cnt[i] += cnt[i - 1]; for (int i = len; i >= 1; i--) sa[cnt[x[rk[i]]]--] = rk[i]; rk[sa[1]] = 1; for (int i = 2; i <= len; i++) rk[sa[i]] = (rk[sa[i - 1]]) + (x[sa[i]] != x[sa[i - 1]] || y[sa[i]] != y[sa[i - 1]]); } } inline void get_height() { int k = 0; for (int i = 1; i <= len; i++) { if (k) --k; int j = sa[rk[i] - 1]; while (s[i + k] == s[j + k]) ++k; height[rk[i]] = k; } } inline void merge(info &x , info y) { x = (info){x.height , x.cnta + y.cnta , x.cntb + y.cntb}; } inline ll calc() { int top = 0; static info s[N]; ll ret = 0 , va = 0 , vb = 0; sa[0] = n + 1; for (int i = 1; i <= len; i++) { info tmp = (info){height[i] , sa[i - 1] < n + 1 , sa[i - 1] > n + 1}; while (top > 0 && height[i] <= s[top].height) { va -= 1ll * s[top].height * s[top].cnta; vb -= 1ll * s[top].height * s[top].cntb; merge(tmp , s[top]); --top; } s[++top] = tmp; va += 1ll * s[top].height * s[top].cnta; vb += 1ll * s[top].height * s[top].cntb; if (sa[i] < n + 1) ret += vb; else ret += va; } return ret; } int main() { scanf("%s%s" , s1 + 1 , s2 + 1); n = strlen(s1 + 1) , m = strlen(s2 + 1); for (int i = 1; i <= n; i++) s[++len] = s1[i]; s[++len] = '#'; for (int i = 1; i <= n; i++) s[++len] = s2[i]; build_sa(); get_height(); printf("%lld\n" , calc()); return 0; }