[AHOI 2013] 差异
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=3238
[算法]
首先 , LCP(Ti , Tj) = min{ height[rank[Ti] + 1] , height[rank[Ti] + 2] , ... , height[rank[Tj]] }
显然 , 我们只要计算后缀两两之间的LCP之和即可
对于一个右端点R , 随着L的减小 , min{height[L] , height[L + 1] .. , height[R]}的值单调递减 , 维护一个单调递增的单调栈即可
时间复杂度 : O(NlogN)
[代码]
#include<bits/stdc++.h> using namespace std; #define MAXN 500010 typedef long long ll; typedef long double ld; const int inf = 1e9; int n; int height[MAXN] , cnt[MAXN] , rk[MAXN] , x[MAXN] , y[MAXN] , sa[MAXN]; char s[MAXN]; inline ll F(int x) { return 1ll * x * (x + 1) / 2; } inline void build_sa() { memset(cnt , 0 , sizeof(cnt)); for (int i = 1; i <= n; i++) ++cnt[(int)s[i]]; for (int i = 1; i <= 256; i++) cnt[i] += cnt[i - 1]; for (int i = n; i >= 1; i--) sa[cnt[(int)s[i]]--] = i; rk[sa[1]] = 1; for (int i = 2; i <= n; i++) rk[sa[i]] = rk[sa[i - 1]] + (s[sa[i]] != s[sa[i - 1]]); for (int k = 1; rk[sa[n]] != n; k <<= 1) { for (int i = 1; i <= n; i++) x[i] = rk[i] , y[i] = (i + k <= n) ? rk[i + k] : 0; memset(cnt , 0 , sizeof(cnt)); for (int i = 1; i <= n; i++) ++cnt[y[i]]; for (int i = 1; i <= n; i++) cnt[i] += cnt[i - 1]; for (int i = n; i >= 1; i--) rk[cnt[y[i]]--] = i; memset(cnt , 0 , sizeof(cnt)); for (int i = 1; i <= n; i++) ++cnt[x[i]]; for (int i = 1; i <= n; i++) cnt[i] += cnt[i - 1]; for (int i = n; i >= 1; i--) sa[cnt[x[rk[i]]]--] = rk[i]; rk[sa[1]] = 1; for (int i = 1; i <= n; 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 <= n; i++) { if (k) --k; int j = sa[rk[i] - 1]; while (s[i + k] == s[j + k]) ++k; height[rk[i]] = k; } } inline ll calc_ans() { int top = 0; ll ret = 0; static pair<ll , ll> s[MAXN]; for (int i = 1; i <= n; i++) ret += 1ll * (i - 1) * (n - i + 1) + F(n) - F(n - i + 1); s[top = 1] = make_pair(0 , 0); ll now = 0; for (int i = 1; i <= n; i++) { int cnt = 1; while (top > 0 && height[i] <= height[s[top].first]) { cnt += s[top].second; now -= 1ll * height[s[top].first] * s[top].second; --top; } s[++top] = make_pair(i , cnt); now += 1ll * height[i] * cnt; ret -= 2ll * now; } return ret; } int main() { scanf("%s" , s + 1); n = strlen(s + 1); build_sa(); get_height(); printf("%lld\n" , calc_ans()); return 0; }