BZOJ3238: [Ahoi2013]差異(字尾自動機)
阿新 • • 發佈:2018-12-14
題意
Sol
前面的可以直接算
然後原串翻轉過來,這時候變成了求任意兩個字首的最長公共字尾,顯然這個值應該是\(len[lca]\),求出\(siz\)亂搞一下
#include<bits/stdc++.h> #define int long long #define LL long long using namespace std; const int MAXN = 1e6 + 10; LL N; char a[MAXN]; int fa[MAXN], len[MAXN], siz[MAXN], ch[MAXN][26], tot = 1, las = 1, root = 1, sum[MAXN]; LL ans; vector<int> v[MAXN]; void insert(int x) { int now = ++tot, pre = las; las = now; len[now] = len[pre] + 1; for(; pre && !ch[pre][x]; pre = fa[pre]) ch[pre][x] = now; if(!pre) fa[now] = root; else { int q = ch[pre][x]; if(len[pre] + 1 == len[q]) fa[now] = q; else { int ns = ++tot; fa[ns] = fa[q]; len[ns] = len[pre] + 1; memcpy(ch[ns], ch[q], sizeof(ch[q])); fa[q] = fa[now] = ns; for(; pre && ch[pre][x] == q; pre = fa[pre]) ch[pre][x] = ns; } } siz[now] = 1; } void Build() { for(int i = 2; i <= tot; i++) v[fa[i]].push_back(i); } LL res = 0; void dp(int x) { for(int i = 0; i < v[x].size(); i++) { int to = v[x][i]; dp(to); res += 1ll * len[x] * siz[x] * siz[to]; siz[x] += siz[to]; } } signed main() { //freopen("a.in", "r", stdin); scanf("%s", a + 1); N = strlen(a + 1); reverse(a + 1, a + N + 1); for(int i = 1; i <= N; i++) insert(a[i] - 'a'); Build(); dp(root); for(int i = 1; i <= N; i++) ans += (LL) (1ll * i * (N - i) + 1ll * (N * (N + 1) / 2 - (i * (i + 1) / 2))); cout << ans - res * 2; return 0; } /* abbabbabbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa */