【bzoj2251】[2010Beijing Wc]外星联络 后缀数组
Description
小 P 在看过电影《超时空接触》(Contact)之后被深深的打动,决心致力于寻
找外星人的事业。于是,他每天晚上都爬在屋顶上试图用自己的收音机收听外星
人发来的信息。虽然他收听到的仅仅是一些噪声,但是他还是按照这些噪声的高
低电平将接收到的信号改写为由 0 和 1 构成的串, 并坚信外星人的信息就隐藏在
其中。他认为,外星人发来的信息一定会在他接受到的 01 串中重复出现,所以
他希望找到他接受到的 01 串中所有重复出现次数大于 1 的子串。但是他收到的
信号串实在是太长了,于是,他希望你能编一个程序来帮助他。
Input
输入文件的第一行是一个整数N ,代表小 P 接收到的信号串的长度。
输入文件第二行包含一个长度为N 的 01 串,代表小 P 接收到的信号串。
Output
输出文件的每一行包含一个出现次数大于1 的子串所出现的次数。输出的顺
序按对应的子串的字典序排列。
Sample Input
7
1010101
1010101
Sample Output
3
3
2
2
4
3
3
2
2
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 }