【BZOJ 3238】【AHOI 2013】差异
http://www.lydsy.com/JudgeOnline/problem.php?id=3238
后缀数组裸题但是\(5\times 10^5\)貌似常数有点大就过不了?(我的sa常数那么大想了想还是算了吧qwq)
两个后缀的lcp就是反串的后缀自动机上两个状态在parent树上的lca,lcp的长度就是lca的maxlen。
这样在parent树上树形dp一下就可以了qwq
时间复杂度\(O(n)\)。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 500003;
struct State {
State *par, *go[26], *point, *nxt;
int val, sz;
} pool[N << 1], *root, *last;
int top = 0;
State *newState(int num) {
State *t = pool + top++;
t->par = t->point = t->nxt = 0;
memset(t->go, 0, sizeof(t->go));
t->val = num; t->sz = 0;
return t;
}
void extend(int w) {
State *p = last;
State *np = newState(p->val + 1); np->sz = 1;
while (p && p->go[w] == 0)
p->go[w] = np, p = p->par;
if (p == 0) np->par = root;
else {
State *q = p->go[w];
if (q->val == p->val +1)
np->par = q;
else {
State *nq = newState(p->val + 1);
memcpy(nq->go, q->go, sizeof(q->go));
nq->par = q->par; q->par = np->par = nq;
while (p && p->go[w] == q)
p->go[w] = nq, p = p->par;
}
}
last = np;
}
char s[N];
int n;
ll ans = 0;
void dfs(State *r) {
for (State *t = r->point; t; t = t->nxt) {
dfs(t);
ans += 1ll * r->val * r->sz * t->sz;
r->sz += t->sz;
}
}
int main() {
scanf("%s", s + 1);
n = strlen(s + 1);
root = last = newState(0);
for (int i = n; i >= 1; --i)
extend(s[i] - 'a');
for (int i = 1; i < top; ++i) {
State *r = pool + i;
r->nxt = r->par->point;
r->par->point = r;
}
dfs(pool);
printf("%lld\n", (1ll * n * (n + 1) * (n - 1) >> 1) - (ans << 1));
return 0;
}
NOI 2017 Bless All