[SPOJ8222]NSUBSTR - Substrings-后缀自动机

NSUBSTR - Substrings

Description

You are given a string S which consists of 250000 lowercase latin letters at most. We define F(x) as the maximal number of times that some string with length x appears in S. For example for string ‘ababa’ F(3) will be 2 because there is a string ‘aba’ that occurs twice. Your task is to output F(i) for every i so that 1<=i<=|S|.

Input

String S consists of at most 250000 lowercase latin letters.

Output

Output |S| lines. On the i-th line output F(i).

Example

Input:

ababa

Output:

3
2
2
1
1

spoj又回归正常了╮(╯▽╰)╭~
然而咱的智商并没有(╯‵□′)╯︵┻━┻
sizeof()打错咱还是头一回……
大触们在发明新方法,而蒟蒻却在发明新错法……

思路:
right数组……
喂这玩意为什么咱以前没有听说过啊啊啊!!!(╯‵□′)╯︵┻━┻
就当是学习了一些人生经验新知识吧~

right数组意义:节点代表的所有的子串的右端点在原串中的位置构成的集合。
那么这个绕口的玩意有什么用呢?
当然有用了,这题的答案就是它的元素个数……

先初始化原串在自动机上跑一边所经过的每一个节点right大小为1。
然后按拓扑序对每个节点传递大小至其父亲,就能求出所有right的大小。
然后用DP跑一边,这题做完了~

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>

using namespace std;

const int N=501233;

struct SAM
{
    int next[N][26],fa[N],len[N];
    int pool,u;

    inline void init()
    {
        pool=u=1;
    }

    inline void add(int v)
    {
        int now=++pool;
        len[now]=len[u]+1;

        while(!next[u][v] && u)
            next[u][v]=now,u=fa[u];

        if(!u)
            fa[now]=1;
        else
        {
            int q=next[u][v];
            if(len[q]==len[u]+1)
                fa[now]=q;
            else
            {
                int newq=++pool;

                memcpy(next[newq],next[q],sizeof(next[q]));//打成sizeof(q)的本蒟蒻智商堪忧......
                fa[newq]=fa[q];
                len[newq]=len[u]+1;
                fa[q]=fa[now]=newq;

                while(next[u][v]==q)
                    next[u][v]=newq,u=fa[u];
            }
        }
        u=now;
    }
}koishi;

int sum[N],id[N],r[N];
int f[N];

int main()
{
    koishi.init();

    char s[N];
    scanf("%s",s+1);
    int len=strlen(s+1);
    for(int i=1;i<=len;++i)
        koishi.add(s[i]-'a');

    int p=1;
    for(int i=1;i<=len;++i)
        p=koishi.next[p][s[i]-'a'],++r[p];

    for(int i=1;i<=koishi.pool;++i)
        ++sum[koishi.len[i]];
    for(int i=1;i<=len;++i)
        sum[i]+=sum[i-1];
    for(int i=1;i<=koishi.pool;++i)
        id[sum[koishi.len[i]]--]=i;

    for(int i=koishi.pool;i;--i)
        r[koishi.fa[id[i]]]+=r[id[i]];

    for(int i=1;i<=koishi.pool;i++)
        f[koishi.len[i]]=max(f[koishi.len[i]],r[i]);
    for(int i=len;i;i--)
        f[i]=max(f[i+1],f[i]);

    for(int i=1;i<=len;i++)
        printf("%d\n",f[i]);

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值