【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\n",r-l);
77         }
78 }

 

posted @ 2018-01-05 13:41  Kaiser-  阅读(165)  评论(0编辑  收藏  举报