#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Node {
int len, link, ch[26];
//额外信息
int cnt, head;
void NewNode(int l = 0) {
len = l, memset(ch, 0, sizeof(ch)), link = 0;
cnt = 1, head = 0;
}
void CopyNewNode(const int &l, const Node& n) {
len = l, memcpy(ch, n.ch, sizeof(ch)), link = n.link;
cnt = 0, head = 0;
}
};
const int MAXN = 1000000;
struct Edge {
int to, next;
} edge[(MAXN << 1) + 5];
int etop;
//SuffixAutomaton
struct SAM {
Node nd[(MAXN << 1) + 5];
int top, last; //top为节点个数,last末尾节点的位置
void init() {
nd[1].NewNode();
top = 1;
}
void extend(char ch) {
int c = ch - 'a';
int p = last, x = last = ++top;
nd[x].NewNode(nd[p].len + 1);
for(; p && !nd[p].ch[c]; p = nd[p].link)
nd[p].ch[c] = x;
if(!p)
nd[x].link = 1;
else {
int q = nd[p].ch[c];
if(nd[p].len + 1 == nd[q].len)
nd[x].link = q;
else {
int y = ++top;
nd[y].CopyNewNode(nd[p].len + 1, nd[q]);
nd[q].link = nd[x].link = y;
for(; p && nd[p].ch[c] == q; p = nd[p].link)
nd[p].ch[c] = y;
}
}
}
void dfs(int id) {
for(int i = nd[id].head; i; i = edge[i].next) {
dfs(edge[i].to);
nd[id].cnt += nd[edge[i].to].cnt;
}
}
ll solve() {
//计算每一种子串的数量
etop = 0;
for(int i = top; i >= 2; --i) {
++etop;
edge[etop].to = i;
edge[etop].next = nd[nd[i].link].head;
nd[nd[i].link].head = etop;
}
dfs(1);
ll res = 0;
for(int i = top; i >= 2; --i)
if(nd[i].cnt > 1) {
ll tmp = 1ll * nd[i].cnt * nd[i].len;
if(tmp > res)
res = tmp;
}
return res;
}
} sam;
char s[MAXN + 5];
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
scanf("%s", s);
sam.init();
for(int i = 0; s[i] != '\0'; ++i)
sam.extend(s[i]);
printf("%lld\n", sam.solve());
}
这个link树不如回文机优美,但是可以用拓扑排序来非递归求。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Node {
int len, link, ch[26];
//额外信息
int cnt;
void NewNode(int l = 0) {
len = l, memset(ch, 0, sizeof(ch)), link = 0;
cnt = 1;
}
void CopyNewNode(const int &l, const Node& n) {
len = l, memcpy(ch, n.ch, sizeof(ch)), link = n.link;
cnt = 0;
}
};
const int MAXN = 1000000;
//SuffixAutomaton
struct SAM {
Node nd[(MAXN << 1) + 5];
int top, last; //top为节点个数,last末尾节点的位置
void init() {
nd[1].NewNode();
top = 1;
}
void extend(char ch) {
int c = ch - 'a';
int p = last, x = last = ++top;
nd[x].NewNode(nd[p].len + 1);
for(; p && !nd[p].ch[c]; p = nd[p].link)
nd[p].ch[c] = x;
if(!p)
nd[x].link = 1;
else {
int q = nd[p].ch[c];
if(nd[p].len + 1 == nd[q].len)
nd[x].link = q;
else {
int y = ++top;
nd[y].CopyNewNode(nd[p].len + 1, nd[q]);
nd[q].link = nd[x].link = y;
for(; p && nd[p].ch[c] == q; p = nd[p].link)
nd[p].ch[c] = y;
}
}
}
int d[(MAXN << 1) + 5];
int que[(MAXN << 1) + 5], front, back;
ll solve() {
//计算每一种子串的数量
memset(d, 0, sizeof(d));
front = 1, back = 0;
for(int i = top; i >= 2; --i)
++d[nd[i].link];
for(int i = top; i >= 2; --i)
if(!d[i])
que[++back] = i;
while(back >= front) {
int u = que[front], v = nd[que[front]].link;
nd[v].cnt += nd[u].cnt;
--d[v];
if(!d[v])
que[++back] = v;
++front;
}
ll res = 0;
for(int i = top; i >= 2; --i)
if(nd[i].cnt > 1) {
ll tmp = 1ll * nd[i].cnt * nd[i].len;
if(tmp > res)
res = tmp;
}
return res;
}
} sam;
char s[MAXN + 5];
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
scanf("%s", s);
sam.init();
for(int i = 0; s[i] != '\0'; ++i)
sam.extend(s[i]);
printf("%lld\n", sam.solve());
}