zoukankan      html  css  js  c++  java
  • 【BZOJ2251】[2010Beijing Wc]外星联络 后缀数组

    【BZOJ2251】[2010Beijing Wc]外星联络 

    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 

    题解:先求出sa和height,然后只要沿着sa枚举每一个子串,在height里找出height不小于当前子串长度的范围。为了防止重复,每次枚举从height+1开始。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int maxn=3010;
    int ra[maxn],rb[maxn],st[maxn],sa[maxn],v[maxn],rank[maxn],h[maxn];
    char str[maxn];
    int n,m;
    void work()
    {
        int i,j,k,p,*x=ra,*y=rb;
        for(i=0;i<n;i++)    st[x[i]=v[i]]++;
        for(i=1;i<m;i++)    st[i]+=st[i-1];
        for(i=n-1;i>=0;i--)    sa[--st[x[i]]]=i;
        for(j=1,p=1;p<n;j<<=1,m=p)
        {
            for(p=0,i=n-j;i<n;i++)    y[p++]=i;
            for(i=0;i<n;i++)    if(sa[i]>=j)    y[p++]=sa[i]-j;
            for(i=0;i<m;i++)    st[i]=0;
            for(i=0;i<n;i++)    st[x[y[i]]]++;
            for(i=1;i<m;i++)    st[i]+=st[i-1];
            for(i=n-1;i>=0;i--)    sa[--st[x[y[i]]]]=y[i];
            for(swap(x,y),p=1,x[sa[0]]=0,i=1;i<n;i++)
                x[sa[i]]=(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j])?p-1:p++;
        }
        for(i=0;i<n;i++)    rank[sa[i]]=i;
        for(i=k=0;i<n-1;h[rank[i++]]=k)
            for(k?k--:0,j=sa[rank[i]-1];v[i+k]==v[j+k];k++);
    }
    int main()
    {
        scanf("%d%s",&n,str);
        int i,j,r;
        for(i=0;i<n;i++)    v[i]=str[i]-'0'+1;
        m=3;
        n++;
        work();
        for(i=1;i<n;i++)
        {
            for(j=h[i]+1;sa[i]+j<n;j++)
            {
                //网上的题解这里还向下求了一下区间的左端点l,感觉不明觉厉 
                for(r=i+1;r<=n&&h[r]>=j;r++);
                if(r-i>=2)    printf("%d
    ",r-i);    
            }
        }
        return 0;
    }
  • 相关阅读:
    python中的itertools模块简单使用
    SQLServer链接服务器
    @Valid和@Validated的区分总结
    禅道完成高成资本独家领投的数千万元融资
    青岛敏捷之旅,来了!
    linux主机互信操作
    小白学标准库之 mux
    小白学标准库之 flag
    音频截取分割打点标注工具
    大数据可能面试题
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6268708.html
Copyright © 2011-2022 走看看