• 【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

    题解:后缀数组,求出height,倍增的方式去求后缀数组

    然后就是裸题了。

     1 #include<cstring>
     2 #include<cmath>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<cstdio>
     6 #include<cstdlib>
     7 
     8 #define N 3007
     9 #define inf 2000000007
    10 #define ll long long
    11 using namespace std;
    12 inline int read()
    13 {
    14     int x=0,f=1;char ch=getchar();
    15     while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    16     while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    17     return x*f;
    18 }
    19 
    20 int n,p,q,k;
    21 int v[N];
    22 char ch[N];
    23 int a[N],h[N];
    24 int rk[2][N],sa[2][N];
    25 
    26 void calsa(int sa[N],int rk[N],int SA[N],int RK[N])
    27 {
    28     for (int i=1;i<=n;i++)
    29         v[rk[sa[i]]]=i;
    30     for (int i=n;i>=1;i--)
    31         if (sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k;
    32     for (int i=n-k+1;i<=n;i++)
    33         SA[v[rk[i]]--]=i;
    34     for (int i=1;i<=n;i++)
    35         RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]]||rk[SA[i]+k]!=rk[SA[i-1]+k]);
    36 }
    37 void work()
    38 {
    39     p=0,q=1;
    40     for (int i=1;i<=n;i++)v[a[i]]++;
    41     for (int i=1;i<=30;i++)v[i]+=v[i-1];
    42     for (int i=1;i<=n;i++)sa[p][v[a[i]]--]=i;
    43     for (int i=1;i<=n;i++)rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);
    44     for (k=1;k<n;k<<=1)
    45     {
    46         calsa(sa[p],rk[p],sa[q],rk[q]);
    47         swap(p,q);
    48     }
    49 }
    50 void get_height()
    51 {
    52     k=0;
    53     for (int i=1;i<=n;i++)
    54         if (rk[p][i]==1) h[rk[p][i]]=0;
    55         else
    56         {
    57             int j=sa[p][rk[p][i]-1];
    58             while(a[i+k]==a[j+k])k++;
    59             h[rk[p][i]]=k;
    60             if (k>0)k--;
    61         }
    62 }
    63 int main()
    64 {
    65     n=read();
    66     scanf("%s",ch+1);
    67     for (int i=1;i<=n;i++)
    68         a[i]=ch[i]-'0'+1;
    69     work(),get_height();
    70     for (int i=1;i<=n;i++)
    71         for (int j=h[i]+1;sa[p][i]+j-1<=n;j++)
    72         {
    73             int l,r;
    74             for (l=i;l>=1&&h[l]>=j;l--);
    75             for (r=i+1;r<=n&&h[r]>=j;r++);
    76             if (r-l>1) printf("%d
    ",r-l);
    77         }
    78 }
  • 相关阅读:
    商务通服务器版LR_Data目录下相关配置文件
    Python入门神图
    你不知道的JavaScript-2.词法作用域
    你不知道的JavaScript-1.作用域是什么
    linux服务器对外打包处理
    C# Form 关闭按钮灰化
    Spread常用属性
    Spread 常用属性
    C#打开关闭窗体事件顺序
    sqlserver如何使用日期计算
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8204008.html
Copyright © 2020-2023  润新知