[洛谷P3804]【模板】后缀自动机

题目大意:给一个只包含小写字母的字符串 $S$ ,请求出 $S$ 的所有出现次数不为 $1$ 的子串的出现次数乘上该子串长度的最大值。

题解:用后缀自动机求出每个字串的长度,排序后求出字串出现次数(后缀自动机是背板的。。。)

卡点:1.$rnk$数组没有开两倍

  板背错

C++ Code:

#include <cstdio>
#include <cstring>
#define maxn 1000010
using namespace std;
char s[maxn << 1];
int nxt[maxn << 1][26], fail[maxn << 1], R[maxn << 1];
int sz[maxn << 1];
int b[maxn], rnk[maxn << 1];
int root, np, p, cnt, t, last, len;
long long ans = -1;
inline long long max(long long a, long long b) {return a > b ? a : b;}
void insert(int ch) {
	int now = ++cnt, np;
	R[now] = R[p = last] + 1;
	sz[now] = 1; last = now;
	for (; ~p && !nxt[p][ch]; p = fail[p]) nxt[p][ch] = now;
	if (!~p) {fail[now] = root; return ;}
	if (R[t = nxt[p][ch]] == R[p] + 1) {fail[now] = t; return ;}
	R[np = ++cnt] = R[p] + 1;
	for (int i = 0; i < 26; i++) nxt[np][i] = nxt[t][i];
	for (fail[np] = fail[t], fail[t] = fail[now] = np; nxt[p][ch] == t; p = fail[p]) nxt[p][ch] = np;
}
int main() {
	scanf("%s", s);
	len = strlen(s);
	fail[root = 0] = -1; cnt = last = 1;
	for (int i = 0; i < len; i++) insert(s[i] - 'a');
	for (int i = 1; i <= cnt; i++) b[R[i]]++;
	for (int i = 1; i <= len; i++) b[i] += b[i - 1];
	for (int i = 1; i <= cnt; i++) rnk[b[R[i]]--] = i;
	for (int i = cnt; i; i--) {
		int now = rnk[i];
		sz[fail[now]] += sz[now];
		if (sz[now] > 1) ans = max(ans, 1ll * sz[now] * R[now]);
	}
	printf("%lld
", ans);
	return 0;
} 

  

原文地址:https://www.cnblogs.com/Memory-of-winter/p/9446696.html