spoj Substrings【后缀自动机】

来源:互联网 发布:网络游戏优化器 编辑:程序博客网 时间:2024/06/05 03:49

题目大意:求一个串里面长度分别为 1 ~ n 的子串中出现次数最多的次数

考虑每个点代表的字符串出现的次数为它right集合的大小,right集合大小可以遍历子树得到,用每个点的right集合大小去更新他 mx 的答案

#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#define N 500005#define INF 1000000000using namespace std;int n,m,last = 1,tot = 1,p,q,np,nq;int son[N][26],par[N],mx[N];int ans[N],f[N],P[N],sm[N];char s[N];int new_node(int x){    mx[++ tot] = x;    return tot;}void add(int x){    p = last;    np = new_node(mx[p] + 1);    for (;p && !son[p][x];p = par[p]) son[p][x] = np;    if (!p) par[np] = 1;    else    {        q = son[p][x];        if (mx[q] == mx[p] + 1) par[np] = q;        else        {            nq = new_node(mx[p] + 1);            memcpy(son[nq],son[q],sizeof(son[nq]));            par[nq] = par[q],par[q] = par[np] = nq;            for (;son[p][x] == q;p = par[p]) son[p][x] = nq;        }    }    f[last = np] ++;}int main(){    scanf("%s",s + 1),n = strlen(s + 1);    for (int i = 1;i <= n;i ++) add(s[i] - 'a');    for (int i = 1;i <= tot;i ++) sm[mx[i]] ++;    for (int i = 1;i <= n;i ++) sm[i] += sm[i - 1];    for (int i = 1;i <= tot;i ++) P[sm[mx[i]] --] = i;    for (int i = tot;i > 1;i --) f[par[P[i]]] += f[P[i]];    for (int i = 1;i <= tot;i ++) ans[mx[i]] = max(ans[mx[i]],f[i]);    for (int i = n;i;i --) f[i] = max(f[i],f[i + 1]);    for (int i = 1;i <= n;i ++) printf("%d\n",ans[i]);    return 0;}
0 0
原创粉丝点击