• 2251: [2010Beijing Wc]外星联络


    2251: [2010Beijing Wc]外星联络

    Time Limit: 30 Sec  Memory Limit: 256 MB
    Submit: 801  Solved: 481
    [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 

    Source

    //后缀数组搞sa,height,对于每个i,枚举一个大于2的长度j,往后扫跟它height>=j的元素。 
    //为了避免重复,j每次枚举时从height[i-1]开始枚举 
    //注意:保证字典序从小到大
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=1e5+7;
    int len,maxx,sa[N],tsa[N],rank[N],trank[N],h[N],c[N];
    char s[N];
    void DA(){
        int p;
        memset(c,0,sizeof c);maxx=256;
        for(int i=1;i<=len;i++) c[rank[i]=s[i]]++;
        for(int i=2;i<=maxx;i++) c[i]+=c[i-1];
        for(int i=len;i;i--) sa[c[rank[i]]--]=i;
        trank[sa[1]]=p=1;
        for(int i=2;i<=len;i++){
            if(rank[sa[i]]!=rank[sa[i-1]]) p++;
            trank[sa[i]]=p;
        }
        for(int i=1;i<=len;i++) rank[i]=trank[i];
        for(int k=1;p<len;k<<=1,maxx=p){
            p=0;
            for(int i=len-k+1;i<=len;i++) tsa[++p]=i;
            for(int i=1;i<=len;i++) if(sa[i]>k) tsa[++p]=sa[i]-k;
            memset(c,0,sizeof c);
            for(int i=1;i<=len;i++) trank[i]=rank[tsa[i]];
            for(int i=1;i<=len;i++) c[trank[i]]++;
            for(int i=2;i<=maxx;i++) c[i]+=c[i-1];
            for(int i=len;i;i--) sa[c[trank[i]]--]=tsa[i];
            trank[sa[1]]=p=1;
            for(int i=2;i<=len;i++){
                if(rank[sa[i]]!=rank[sa[i-1]]||rank[sa[i]+k]!=rank[sa[i-1]+k]) p++;
                trank[sa[i]]=p;
            }
            for(int i=1;i<=len;i++) rank[i]=trank[i];
        }
        for(int i=1,k=0;i<=len;i++){
            int j=sa[rank[i]-1];
            while(s[i+k]==s[j+k]) k++;
            h[rank[i]]=k;if(k>0) k--;
        }
    }
    int main(){
        scanf("%d%s",&len,s+1);
        DA();
        for(int i=2,pre=0;i<=len;i++){
            for(int j=pre+1;j<=h[i];j++){
                int ans=1,k=i;
                while(h[k]>=j) k++,ans++;
                printf("%d
    ",ans);
            }
            pre=h[i];
        }
        return 0;
    }
  • 相关阅读:
    MySQL运维案例分析:Binlog中的时间戳
    身边有位“别人家的程序员”是什么样的体验?
    苹果收取30%过路费_你是顶是踩?
    1019 数字黑洞 (20 分)C语言
    1015 德才论 (25 分)C语言
    1017 A除以B (20 分)C语言
    1014 福尔摩斯的约会 (20 分)
    求n以内最大的k个素数以及它们的和、数组元素循环右移问题、求最大值及其下标、将数组中的数逆序存放、矩阵运算
    1005 继续(3n+1)猜想 (25 分)
    爬动的蠕虫、二进制的前导的零、求组合数、Have Fun with Numbers、近似求PI
  • 原文地址:https://www.cnblogs.com/shenben/p/6295460.html
Copyright © 2020-2023  润新知