BZOJ3238: [Ahoi2013]差异(后缀自动机)
题意
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
*/
作者:自为风月马前卒
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。