• BZOJ_2251_[2010Beijing Wc]外星联络_后缀数组


    BZOJ_2251_[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数组。

    然后从前往后枚举子串,向后扩展,直到某个height[i]小于枚举子串的长度。

    需要注意枚举的子串长度应该从height[i]+1开始枚举,因为比它短的那些子串在前面已经枚举过了。

    时间复杂度O(nlogn+答案)<=O(n^2)。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 3050
    int n,ws[N],wv[N],wa[N],wb[N],sa[N],m=3,r[N];
    int rank[N],height[N];
    char str[N];
    void build_suffix_array() {
        int i,j,p,*x=wa,*y=wb,*t;
        for(i=0;i<m;i++) ws[i]=0;
        for(i=0;i<n;i++) ws[x[i]=r[i]]++;
        for(i=1;i<m;i++) ws[i]+=ws[i-1];
        for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
        for(j=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>=0) y[p++]=sa[i]-j;
            for(i=0;i<n;i++) wv[i]=x[y[i]];
            for(i=0;i<m;i++) ws[i]=0;
            for(i=0;i<n;i++) ws[wv[i]]++;
            for(i=1;i<m;i++) ws[i]+=ws[i-1];
            for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
            for(t=x,x=y,y=t,x[sa[0]]=0,p=i=1;i<n;i++) {
                if(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]) x[sa[i]]=p-1;
                else x[sa[i]]=p++;
            }
        }
        for(i=1;i<n;i++) rank[sa[i]]=i;
        for(i=p=0;i<n-1;height[rank[i++]]=p)
            for(p?p--:0,j=sa[rank[i]-1];r[i+p]==r[j+p];p++);
    }
    int main() {
        scanf("%d",&n);
        scanf("%s",str);
        int i,j,k;
        for(i=0;i<n;i++) r[i]=str[i]-'0'+1;
        n++;
        build_suffix_array();
        for(i=1;i<=n;i++) {
            for(j=height[i]+1;sa[i]+j-1<n;j++) {
                for(k=i+1;height[k]>=j&&k<=n;k++) ;
                if(k-i>1) printf("%d
    ",k-i);
            }
        }
    }
    
  • 相关阅读:
    主从复制(多台服务器搭建环境)【十五】
    Linux中kill,pkill,killall和xkill命令汇总讲解
    redis持久化机制【十三】
    守护进程详解及创建,daemon()使用
    【small项目】MySQL第二天早上第一次连接超时报错,解决方法com.mysql.jdbc.exceptions.jdbc4.CommunicationsException:
    Redis事务【十二】
    乐观锁和悲观锁的区别
    Redis 命令与连接【十一】
    Redis 配置【十】
    DB_Links创建际删除
  • 原文地址:https://www.cnblogs.com/suika/p/9203707.html
Copyright © 2020-2023  润新知