zoukankan      html  css  js  c++  java
  • 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

    这个题是bzoj权限题QvQ
    于是只好自己和hzwer学长的标称对拍
    其实一开始我的思路是差不多的
    构造后缀数组,字典序为SA,然后随便枚举一下
    只不过我忽略了一个重要的性质
    使得我的效率变成了O(n^3)
    然而只要用到下面这个性质,效率就只有O(n^2):
    因为子串是后缀的前缀,
    而SA[i]和SA[i-1]的前height[i]位本质又是相同的,
    因重复的子串在SA[i-1]已经往后扫过了
    所以串SA[i]只需要判断height[i]+1位~最后一位构成的前缀能往后扩展多少即可。
    原因:每个子串只出现过一次,共n^2个子串

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define MAXN (3000+10)
     5 using namespace std;
     6 int wa[MAXN],wb[MAXN],wt[MAXN];
     7 char r[MAXN];
     8 int Height[MAXN],SA[MAXN],Rank[MAXN];
     9 int n,m=130; 
    10 
    11 bool cmp(int *y,int a,int b,int k)
    12 {
    13     int arank1=y[a];
    14     int brank1=y[b];
    15     int arank2=a+k>=n?-1:y[a+k];
    16     int brank2=b+k>=n?-1:y[b+k];
    17     return arank1==brank1 && arank2==brank2;
    18 }
    19 
    20 void Build_SA()
    21 {
    22     int *x=wa,*y=wb;
    23     for (int i=0;i<m;++i) wt[i]=0;
    24     for (int i=0;i<n;++i) wt[x[i]=r[i]]++;
    25     for (int i=1;i<m;++i) wt[i]+=wt[i-1];
    26     for (int i=n-1;i>=0;--i) SA[--wt[x[i]]]=i;
    27     
    28     for (int j=1;j<=n;j<<=1)
    29     {
    30         int p=0;
    31         for (int i=n-j;i<n;++i) y[p++]=i;
    32         for (int i=0;i<n;++i) if (SA[i]>=j) y[p++]=SA[i]-j;
    33         
    34         for (int i=0;i<m;++i) wt[i]=0;
    35         for (int i=0;i<n;++i) wt[x[y[i]]]++;
    36         for (int i=1;i<m;++i) wt[i]+=wt[i-1];
    37         for (int i=n-1;i>=0;--i) SA[--wt[x[y[i]]]]=y[i];
    38         
    39         m=1;swap(x,y);
    40         x[SA[0]]=0;
    41         for (int i=1;i<n;++i)
    42             x[SA[i]]=cmp(y,SA[i],SA[i-1],j)?m-1:m++;
    43         if (m>=n) break;
    44     }
    45 }
    46 
    47 void Build_Height()
    48 {
    49     for (int i=0;i<n;++i) Rank[SA[i]]=i;
    50     Height[0]=0;
    51     int k=0;
    52     for (int i=0;i<n;++i)
    53     {
    54         if (!Rank[i]) continue;
    55         if (k) k--;
    56         int j=SA[Rank[i]-1];
    57         while (r[i+k]==r[j+k]) ++k;
    58         Height[Rank[i]]=k;
    59     }
    60 }
    61 
    62 int main()
    63 {
    64     scanf("%d%s",&n,r);
    65     Build_SA();
    66     Build_Height();
    67     for (int i=0;i<n-1;++i)
    68     {
    69         for (int j=Height[i]+1;j<=n-SA[i];++j)//这里非常的妙啊 
    70         {
    71             int k=i+1;
    72             while (Height[k]>=j) ++k;
    73             if (k-i>1) printf("%d
    ",k-i);
    74         }
    75     }
    76 }
  • 相关阅读:
    JVM发生OOM调优
    行云创新完成B轮融资,阿里云独家投资
    行云创新直播回顾:DDD“爱”上Dapr
    如何通过Dapr快速实现DDD?
    通过Dapr快速落地DDD,实现高并发
    上K8s,研发团队如何从容一点?
    直播来了!等你围观!聊聊服务网格那些事儿
    服务网格出现流量故障该咋办?SolarMesh发布重大功能
    mysql 授权问题
    Centos Mysql5.7 安装
  • 原文地址:https://www.cnblogs.com/refun/p/8679064.html
Copyright © 2011-2022 走看看