• SPOJ bsubstr


    题目大意:给你一个长度为n的字符串,求出所有不同长度的字符串出现的最大次数。

    n<=250000

    如:abaaa

    输出:

    4

    2

    1

    1

    1

    spoj上的时限卡的太严,必须使用O(N)的算法那才能过掉,所以采用后缀自动机解决。

    一个字符串出现的次数,即为后缀自动机中该字符串对应的节点的right集合的大小,right集合的大小等于子树中叶子节点的数目。

    令dp[i]表示长度为i的字符串出现的最大次数。dp[i]可以通过在后缀链接树中从叶子节点到根节点依次求出。

    最后,按长度从大到小,用dp[i]去更新dp[i-1]。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    using namespace std;
    #define MAXN 250005
    #define MAXC 26
    struct node
    {
        int go[MAXC],sufflink,step,right;
        void clear()
        {memset(go,0,sizeof go);
            sufflink=step=right=0;
        }
    }tree[MAXN<<1];
    int dp[MAXN],cnt[MAXN],rk[MAXN<<1],root,tot,cur,last,len,ans;
    char s[MAXN];
    void insert(int val)
    {
        int p,q;
        tree[last].go[val]=++tot;
        cur=tot;
        tree[cur].clear();
        tree[cur].step=tree[last].step+1;
        tree[cur].right++;
        for(p=tree[last].sufflink;p&&tree[p].go[val]==0;p=tree[p].sufflink)
            tree[p].go[val]=cur;
        if(p==0)
        tree[cur].sufflink=root;
        else
        {
            q=tree[p].go[val];
            if(tree[p].step+1==tree[q].step)
            tree[cur].sufflink=q;
            else
            {
                tree[++tot].clear();
                tree[tot]=tree[q];
                tree[tot].right=0;
                tree[tot].step=tree[p].step+1;
                tree[cur].sufflink=tree[q].sufflink=tot;
                for(;tree[p].go[val]==q;p=tree[p].sufflink)
                    tree[p].go[val]=tot;
                }
        }
        last=cur;
    }
    void calc()
    {
        int temp;
        for(int i=1;i<=tot;i++)cnt[tree[i].step]++;
        for(int i=1;i<=len;i++)cnt[i]+=cnt[i-1];
        for(int i=1;i<=tot;i++)rk[cnt[tree[i].step]--]=i;
        for(int i=tot;i>1;i--)
        {
            temp=tree[rk[i]].sufflink;
            if(tree[rk[i]].right>dp[tree[rk[i]].step])dp[tree[rk[i]].step]=tree[rk[i]].right;
            if(temp)tree[temp].right+=tree[rk[i]].right;
        }
        for(int i=len-1;i>=1;i--)
            if(dp[i+1]>dp[i])dp[i]=dp[i+1];
        for(int i=1;i<=len;i++)
        printf("%d
    ",dp[i]);
    }
    int main()
    {
        while(~scanf("%s",s))
        {
        root=last=cur=tot=1;
            tree[1].clear();
        memset(dp,0,sizeof dp);
        memset(cnt,0,sizeof cnt);
         len=strlen(s);
        for(int i=0;i<len;i++)
            insert(s[i]-'a');
        calc();
    }
        return 0;
  • 相关阅读:
    insertAfter()
    Unity3D之协程(Coroutines & Yield )
    C#中 As 和强制转换的总结
    Mesh系列文章
    在Unity3D 4中关联Visual Studio 2012来编写C#
    Unity3D安装多版本
    Time.deltaTime 增量时间
    Unity3D中Update和Lateupdate的区别
    Making raycast ignore multiple layers
    Unity3d中SendMessage 用法简单笔记
  • 原文地址:https://www.cnblogs.com/hefenghhhh/p/5083187.html
Copyright © 2020-2023  润新知