题意
给定一个只包含小写字母的字符串 S,
请你求出 S 的所有出现次数不为 1 的子串的出现次数乘上该子串长度的最大值。
思路
后缀自动机,parent树上dfs。
code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
const int maxm = maxn<<1;
long long ans = 0;
struct SAM {
int len[maxm], link[maxm], cnt[maxm];
int a[maxm], c[maxm];
int nxt[maxm][26];
int last, tot;
int head[maxm], v[maxm], nt[maxm], num;
void addEdge(int u, int _v) {
v[num] = _v, nt[num] = head[u];
head[u] = num++;
}
// vector<int> g[maxn<<1];
void init() {
len[0] = link[0] = 0;
last = tot = 1;
}
void extend(int c) {
c -= 'a';
int cur = ++tot, p = last;
len[cur] = len[last] + 1;
cnt[cur] = 1;
for (; p && !nxt[p][c]; p = link[p]) nxt[p][c] = cur;
if(!p) {
link[cur] = 1;
} else {
int q = nxt[p][c];
if(len[q] == len[p]+1) {
link[cur] = q;
} else {
int clone = ++tot;
len[clone] = len[p] + 1;
memcpy(nxt[clone], nxt[q], sizeof(nxt[q]));
link[clone] = link[q];
for (; p && nxt[p][c]==q; p=link[p]) nxt[p][c] = clone;
link[q] = link[cur] = clone;
}
}
last = cur;
}
void build() {
for (int i = 1; i <= tot; ++i) head[i] = -1; num = 0;
for (int i = 2; i <= tot; ++i)
addEdge(link[i], i);
}
void dfs(int x) { // parent树上dfs, vector T了, 前向星2.98s, mx = 494ms
for (int i = head[x]; ~i; i=nt[i]) {
dfs(v[i]);
cnt[x] += cnt[v[i]];
}
if(cnt[x] > 1) ans = max(ans, 1ll*cnt[x]*len[x]);
}
void count() { // 利用基数排序模拟dfs过程 , 3.65s, mx = 982ms
long long ans = 0;
for (int i = 1; i <= tot; ++i) ++c[len[i]];
for (int i = 1; i <= tot; ++i) c[i] += c[i-1];
for (int i = 1; i <= tot; ++i) a[c[len[i]]--] = i;
for (int i = tot; i; --i) {
int p = a[i];
cnt[link[p]] += cnt[p];
if(cnt[p]>1) ans = max(ans, 1ll*cnt[p]*len[p]);
}
printf("%lld
", ans);
}
}sam;
char str[maxn];
int main() {
sam.init();
scanf("%s", str);
for (int i = 0; str[i]; ++i) sam.extend(str[i]);
sam.build();
sam.dfs(1);
printf("%lld
", ans);
// sam.count();
return 0;
}