[tyvj1860]后缀数组

题目链接:http://www.tyvj.cn/p/1860

解题关键:模板题。贴一个代码详解

http://www.cnblogs.com/staginner/archive/2012/02/02/2335600.html

注意:一个字符串中的所有子串都必然是它的后缀的前缀

da算法,必须保证字符串中每个字符的映射>=1

注意点:sa从0~n-1,rank1数组和height数组从1-n

height[1]恒为0

 1 #include<cstdlib>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<iostream>
 6 #include<cmath>
 7 using namespace std;
 8 const int N=200005;
 9 int wa[N],wb[N],wv[N],wc[N];
10 bool cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}//比较两个字符串是否完全相同 
11 void make_sa(int *r,int *sa,int n,int m){//最大值小于m 
12     int i,j,p,*x=wa,*y=wb;//x,y是指针 
13     for(i=0;i<m;i++) wc[i]=0;
14     for(i=0;i<n;i++) wc[x[i]=r[i]]++;
15     for(i=1;i<m;i++) wc[i]+=wc[i-1];
16     for(i=n-1;i>=0;i--) sa[--wc[x[i]]]=i;//基数排序
17     for(j=1,p=1;p<n;j*=2,m=p){
18         for(p=0,i=n-j;i<n;i++) y[p++]=i;
19         for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;//y是第二关键词的sa 
20         for(i=0;i<n;i++) wv[i]=x[y[i]];
21         for(i=0;i<m;i++) wc[i]=0;
22         for(i=0;i<n;i++) wc[wv[i]]++;
23         for(i=1;i<m;i++) wc[i]+=wc[i-1];
24         for(i=n-1;i>=0;i--) sa[--wc[wv[i]]]=y[i];
25         for(swap(x,y),p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;//x是rank数组,1 1 2 2 2 3 这种 
26     }
27     return;
28 }
29 int rank1[N],height[N],sa[N];//注意sa和rank的对应关系,sa的数值从0开始,rank的数值从1开始 
30 void make_height(int *r,int *sa,int n){
31     int i,j,k=0;
32     for(i=1;i<=n;i++) rank1[sa[i]]=i;
33     for(i=0;i<n;height[rank1[i++]]=k)
34         for(k?k--:0,j=sa[rank1[i]-1];r[i+k]==r[j+k];k++);
35     return;
36 }
37 //sa是名次所在位置,rank是位置所在名次
38 int r[N<<1];
39 int main() {
40     ios::sync_with_stdio(0);
41     int n=0;
42     string s;
43     cin>>s;
44     for(int i=0;i<s.size();i++) r[n++]=s[i]-'a'+1; r[n]=0;
45     make_sa(r,sa,n+1,27);
46     make_height(r,sa,n);
47     for(int i=1;i<=n;i++) cout<<sa[i]+1<<" ";cout<<"\n";//这里的1是逻辑上的首位 
48     for(int i=1;i<=n;i++) cout<<height[i]<<" ";cout<<"\n";
49 }

 

 

 下面这种调用方式更无脑一些

 1 #include <cstdlib>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5 #include<iostream>
 6 #include<cstdlib>
 7 using namespace std;
 8 
 9 const int N = 200005;
10 int wa[N],wb[N],wv[N],wc[N];
11 
12 bool cmp(int *r,int a,int b,int l){
13     return r[a]==r[b]&&r[a+l]==r[b+l];
14 }
15 
16 void make_sa(int *r,int *sa,int n,int m){//m是至多有多少个字符,up的意思
17     int i,j,p,*x=wa,*y=wb;
18     for(i=0;i<m;i++) wc[i]=0;
19     for(i=0;i<n;i++) wc[x[i]=r[i]]++;
20     for(i=1;i<m;i++) wc[i]+=wc[i-1];
21     for(i=n-1;i>=0;i--) sa[--wc[x[i]]]=i;
22     for(j=1,p=1;p<n;j*=2,m=p){
23         for(p=0,i=n-j;i<n;i++) y[p++]=i;
24         for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
25         for(i=0;i<n;i++) wv[i]=x[y[i]];
26         for(i=0;i<m;i++) wc[i]=0;
27         for(i=0;i<n;i++) wc[wv[i]]++;
28         for(i=1;i<m;i++) wc[i]+=wc[i-1];
29         for(i=n-1;i>=0;i--) sa[--wc[wv[i]]]=y[i];
30         for(swap(x,y),p=1,x[sa[0]]=0,i=1;i<n;i++)
31             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
32     }
33     return;
34 }
35 
36 int rank1[N],height[N],sa[N];//输出都是从1开始存的,rank从0开始,最后需要+1,读入从下标0
37 void make_height(int *r,int *sa,int n){
38     int i,j,k=0;
39     for(i=1;i<=n;i++) rank1[sa[i]]=i;
40     for(i=0;i<n;height[rank1[i++]]=k)
41         for(k?k--:0,j=sa[rank1[i]-1];r[i+k]==r[j+k];k++);
42     return;
43 }
44 //sa是名次所在位置,rank是位置所在名次
45 int r[N];
46 int main() {
47     ios::sync_with_stdio(0);
48     cin.tie(0);
49     cout.tie(0);
50     string s;
51     cin>>s;
52     for(int i=0;i<s.size();i++) r[i]=(int)s[i];
53     int t=(int)s.size();
54     r[t]=0;
55     make_sa(r, sa,t+1,128);//注意+1,因为补0的原因
56     make_height(r, sa, t);
57     for(int i=1;i<=t;i++) cout<<sa[i]+1<<" ";
58     cout<<"\n";
59     for(int i=1;i<=t;i++) cout<<height[i]<<" ";
60     cout<<"\n";
61     return 0;
62 }

 

后缀数组练习

poj2774 最长公共子串问题,将两个字符串接在一起解决。height数组就代表lcp(最长公共前缀)

 1 #include <cstdlib>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5 #include<iostream>
 6 #include<cstdlib>
 7 using namespace std;
 8 const int N=200005;
 9 int wa[N],wb[N],wv[N],wc[N],n,m;
10 bool cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
11 void make_sa(int *r,int *sa,int n,int m){
12     int i,j,p,*x=wa,*y=wb;
13     for(i=0;i<m;i++) wc[i]=0;
14     for(i=0;i<n;i++) wc[x[i]=r[i]]++;
15     for(i=1;i<m;i++) wc[i]+=wc[i-1];
16     for(i=n-1;i>=0;i--) sa[--wc[x[i]]]=i;
17     for(j=1,p=1;p<n;j*=2,m=p){
18         for(p=0,i=n-j;i<n;i++) y[p++]=i;
19         for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
20         for(i=0;i<n;i++) wv[i]=x[y[i]];
21         for(i=0;i<m;i++) wc[i]=0;
22         for(i=0;i<n;i++) wc[wv[i]]++;
23         for(i=1;i<m;i++) wc[i]+=wc[i-1];
24         for(i=n-1;i>=0;i--) sa[--wc[wv[i]]]=y[i];
25         for(swap(x,y),p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
26     }
27     return;
28 }
29 int rank1[N],height[N],sa[N];
30 void make_height(int *r,int *sa,int n){
31     int i,j,k=0;
32     for(i=1;i<=n;i++) rank1[sa[i]]=i;
33     for(i=0;i<n;height[rank1[i++]]=k)
34         for(k?k--:0,j=sa[rank1[i]-1];r[i+k]==r[j+k];k++);
35     return;
36 }
37 
38 int r[N<<1];
39 int main() {
40     ios::sync_with_stdio(0);
41     string s,t;
42     cin>>s>>t;
43     int n=0;
44     for(int i=0;i<s.size();i++) r[n++]=s[i]-'a'+1; r[n++]=27;int sl=n;
45     for(int i=0;i<t.size();i++) r[n++]=t[i]-'a'+1; r[n]=0;
46     make_sa(r, sa, n+1, 28);
47     make_height(r, sa, n);
48     int ans=0;
49     for(int i=1;i<n;i++){
50         if((sa[i]<sl)!=(sa[i+1]<sl)){
51             ans=max(ans,height[i+1]);
52         }
53     }
54     cout<<ans<<"\n";
55     return 0;
56 }
View Code

 

posted @ 2017-08-10 21:25  Elpsywk  阅读(153)  评论(0编辑  收藏  举报