【前置知识】
AC自动机(没有什么关联,但是看懂了会对后缀自动机有不同的理解)
【解决问题】
各种子串的问题
【算法学习】
学习后缀自动机的过程中,看到了许多相关性质和证明,但是奈何才疏学浅(lan)
暂时先放着,到有空再更
【算法分析】
后缀自动机和AC自动机和回文自动机的不同点在于
后缀自动机是个DAG,而AC自动机和回文自动机是树
首先理解 endpos 数组,每个子串都有一个endpos数组,表示他在字符串中出现的位置的结束位置
而endpos数组相同的子串,就被称为endpos类
而显然易见的,endpos类中最长的子串,能够在子类中找到他的所有子串
而后缀自动机中的节点,就是endpos类,所代表的字符串,也可以表示为这个endpos类中最长的子串
节点之间的边,是互相之间的字母
通过字母走到节点,能够得到关于这个节点子串的后缀
即此节点所代表的整个 endpos 类
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> #define ll long long using namespace std; const int MAXN = 2*1e6 + 10; const int CHAR = 27; struct note { int ch[CHAR]; int fa; ll len; }dian[MAXN]; int zhi[MAXN]; int cnt=1, now=1; char s[MAXN]; void insert(int c) { int p = now, np = now = ++cnt; zhi[cnt] = 1; dian[np].len = dian[p].len + 1; for (;p && !dian[p].ch[c]; p = dian[p].fa) dian[p].ch[c] = np; if (!p) dian[np].fa = 1; else { int q = dian[p].ch[c]; if (dian[q].len == dian[p].len + 1) dian[np].fa = q; else { int nq = ++cnt; dian[nq] = dian[q]; dian[nq].len = dian[p].len + 1; dian[q].fa = dian[np].fa = nq; for (; p && dian[p].ch[c] == q; p = dian[p].fa) dian[p].ch[c] = nq; } } } ll ans = 0; int cd; int st[MAXN],top; struct NOTE { int to; int nt; }edge[MAXN]; void add(int x, int y) { top++; edge[top].nt = st[x]; edge[top].to = y; st[x] = top; } void dfs(int x) { for (int i = st[x]; i != -1; i = edge[i].nt) { dfs(edge[i].to); zhi[x] += zhi[edge[i].to]; } if (zhi[x] != 1) ans = max(ans, zhi[x] * dian[x].len); } int main() { memset(st, -1, sizeof(st)); scanf("%s", s); cd = strlen(s); //printf("**\n"); for (int i = 0; i < cd; i++) insert(s[i] - 'a'+1); //printf("**\n"); for (int i = 2; i <= cnt; i++) add(dian[i].fa, i); //printf("**\n"); dfs(1); printf("%lld\n", ans); return 0; }