后缀自动机板子题
题意:给了一个字符串,然后里面有些子串出现次数大于1,求这种子串的出现次数乘以子串长度的最大值。
思路:
- 正常建好后缀自动机,将所有的np节点出现次数赋值为1
- 记录所有的父节点有几个儿子(不是后缀自动机上的儿子数,而是parent tree上的儿子数)
- 利用topo排序的思路更新所有节点的出现次数
- 然后就是更新答案
//#pragma comment(linker, "/STACK:102400000,102400000")
#include "bits/stdc++.h"
#define pb push_back
#define ls l,m,now<<1
#define rs m+1,r,now<<1|1
#define hhh printf("hhh\n")
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline int read() {int x=0;char c=getchar();while(c<'0'||c>'9')c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return x;}
const int maxn = 1e6+10;
const int mod = 1e9+7;
const double eps = 1e-9;
char s[maxn];
int ch[maxn*2][26], len[maxn*2], fa[maxn*2];
int cnt[maxn*2], son[maxn*2];
int last=1, sz=1, n;
bool cmp(int a, int b) {
return len[a]>len[b];
}
void add(int c) {
int p=last, np=last=++sz;
len[np]=len[p]+1; cnt[np]=1;
for(; p&&!ch[p][c]; p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=1;
else {
int q=ch[p][c];
if(len[q]==len[p]+1) fa[np]=q;
else {
int nq=++sz;
fa[nq]=fa[q], len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],104);
fa[q]=fa[np]=nq;
for(; p&&ch[p][c]==q; p=fa[p]) ch[p][c]=nq;
}
}
}
int main() {
//ios::sync_with_stdio(false);
scanf("%s", s); n=strlen(s);
for(int i=0; i<n; ++i) add(s[i]-'a');
queue<int> q;
for(int i=1; i<=sz; ++i) son[fa[i]]++;
for(int i=1; i<=sz; ++i) if(!son[i]) q.push(i);
while(q.size()) {
int now=q.front(); q.pop();
cnt[fa[now]]+=cnt[now];
son[fa[now]]--;
if(!son[fa[now]]) q.push(fa[now]);
}
ll ans=0;
for(int i=1; i<=sz; ++i) if(cnt[i]>1) ans=max(ans,1LL*cnt[i]*len[i]);
cout<<ans<<endl;
}