【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;
}
posted @ 2017-03-30 21:26  abclzr  阅读(178)  评论(0编辑  收藏  举报