zoukankan      html  css  js  c++  java
  • bzoj 2251: [2010Beijing Wc]外星联络 后缀数组

    2251: [2010Beijing Wc]外星联络

    Time Limit: 30 Sec  Memory Limit: 256 MB
    Submit: 424  Solved: 232
    [Submit][Status][Discuss]

    Description

    小 P 在看过电影《超时空接触》(Contact)之后被深深的打动,决心致力于寻
    找外星人的事业。于是,他每天晚上都爬在屋顶上试图用自己的收音机收听外星
    人发来的信息。虽然他收听到的仅仅是一些噪声,但是他还是按照这些噪声的高
    低电平将接收到的信号改写为由 0 和 1 构成的串, 并坚信外星人的信息就隐藏在
    其中。他认为,外星人发来的信息一定会在他接受到的 01 串中重复出现,所以
    他希望找到他接受到的 01 串中所有重复出现次数大于 1 的子串。但是他收到的
    信号串实在是太长了,于是,他希望你能编一个程序来帮助他。

    Input

    输入文件的第一行是一个整数N ,代表小 P 接收到的信号串的长度。
    输入文件第二行包含一个长度为N 的 01 串,代表小 P 接收到的信号串。

    Output

    输出文件的每一行包含一个出现次数大于1 的子串所出现的次数。输出的顺
    序按对应的子串的字典序排列。

    Sample Input

    7
    1010101

    Sample Output

    3
    3
    2
    2
    4
    3
    3
    2
    2

    HINT

      对于 100%的数据,满足 0 <=  N     <=3000

      按理说以前写过的算法模板题就不该再写了,但是我后缀数组掌握的确实跟xiang一样,还是再写一遍。

      后缀数组需要将内存开大两倍,这个问题我就不赘述了。主要问题是求height数组,以前总觉得顺序问题很烦,其实也不难,只要搞清楚求height的转移顺序就行,一个位置的height求取就需要它在“字符串位置”中前一个位置的height值就行了,所以for语句应该一次枚举原数组的位置。

      剩下就比较简单了,我用O(n^2)的时间复杂度处理答案,不知道有没有更快的,一点小的注意事项,字典序排序注意起始位置相同的子串的顺序,其顺序与枚举顺序相反。也就是说我们在绕过一个坑的情况下防止跌进另一个坑中。

      最后hbw提到一个将随机字符串后缀数组优化到O(n)的方法,当rank数组最大值为n时直接break掉,貌似这是个简单有用的优化

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define MAXN 3010*2
    char str[MAXN];
    int sa[MAXN],tsa[MAXN];
    int rank[MAXN],trank[MAXN];
    int buc[MAXN];
    int height[MAXN];
    int theight[MAXN];
    void IndexSort(int jp,int n)
    {
            memset(buc,0,sizeof(buc));
            for (int i=0;i<n;i++)buc[rank[i+jp]]++;
            for (int i=1;i<=n;i++)buc[i]+=buc[i-1];
            for (int i=n-1;i>=0;i--)tsa[--buc[rank[i+jp]]]=i;
            memset(buc,0,sizeof(buc));
            for (int i=0;i<n;i++)buc[rank[tsa[i]]]++;
            for (int i=1;i<=n;i++)buc[i]+=buc[i-1];
            for (int i=n-1;i>=0;i--)sa[--buc[rank[tsa[i]]]]=tsa[i];
    }
    void SuffixArray(char* str,int n)
    {
            for (int i=0;i<n;i++)trank[i]=str[i]-'0'+1;
            for (int i=0;i<n;i++)buc[trank[i]]++;
            for (int i=1;i<=n;i++)buc[i]+=buc[i-1];
            for (int i=n-1;i>=0;i--)sa[--buc[trank[i]]]=i;
            for (int i=0,x=0;i<n;i++)
            {
                    if (!i || trank[sa[i]]!=trank[sa[i-1]])x++;
                    rank[sa[i]]=x;
            }
            for (int j=1;j<n;j=j<<1)
            {
                    IndexSort(j,n);
                    int x=0;
                    for (int i=0;i<n;i++)
                    {
                            if (!i || rank[sa[i]]!=rank[sa[i-1]] || rank[sa[i]+j]!=rank[sa[i-1]+j])x++;
                            trank[sa[i]]=x;
                    }
                    for (int i=0;i<n;i++)rank[i]=trank[i];
                    if (x==n)break;
            }
    }
    void InitHeight(int n)
    {
            for (int i=0;i<n;i++)
            {
                    if (rank[i]==1)continue;
                    height[i]=max(height[i-1]-1,0);
                    while (i+height[i]<n && sa[rank[i]-2]+height[i]<n 
                                    && str[i+height[i]]==str[sa[rank[i]-2]+height[i]])
                            height[i]++;
            }
            for (int i=1;i<n;i++)
                    theight[i]=height[sa[i]];
    }
    vector<int> vec;
    int stack[MAXN],tops=-1;
    int main()
    {
            freopen("input.txt","r",stdin);
            int n;
            int x;
            scanf("%d
    ",&n);
            scanf("%s
    ",str);
            SuffixArray(str,n);
            InitHeight(n);
        //    for (int i=0;i<n;i++)printf("%d ",sa[i]);printf("
    ");
        //    for (int i=0;i<n;i++)printf("%s
    ",str+sa[i]);printf("
    ");
        //    for (int i=0;i<n;i++)printf("%d ",height[i]);printf("
    ");
            for (int i=1;i<n;i++)
            {
                    if (theight[i]<=theight[i-1])continue;
                    x=i;
                    for (int k=theight[i];k>theight[i-1];k--)
                    {
                            while (x+1<n && theight[x+1]>=k)x++;
                            stack[++tops]=x-i+2;
                    }
                    while (~tops)
                            printf("%d
    ",stack[tops--]);
            }
    }
    by mhy12345(http://www.cnblogs.com/mhy12345/) 未经允许请勿转载

    本博客已停用,新博客地址:http://mhy12345.xyz

  • 相关阅读:
    目录
    mysql 常用命令复习
    mysql备份及pymysql
    mysql 表操作
    mysql 库操作
    mysql 数据库
    各种推导式
    python 之I/O模型
    python 之进程
    python之 多线程(二)
  • 原文地址:https://www.cnblogs.com/mhy12345/p/4356322.html
Copyright © 2011-2022 走看看