用 二分+哈希 求后缀数组

  个人感觉后缀数组的板子太难背了,听了小火车讲二分+哈希可以实现求后缀数组,貌似很好理解,代码如下。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<queue>
 8 #include<vector>
 9 #include<ctime>
10 using namespace std;
11 typedef unsigned long long ULL;
12 const ULL BASE=127;
13 const int maxn=6000000;
14 ULL base[maxn],hash[maxn];
15 int len;
16 char s[maxn];
17 inline ULL get_hash(int l,int r){
18     return hash[r]-hash[l-1]*base[r-l+1];
19 }
20 struct S{
21     int pos;
22 }suf[maxn];
23 inline int find(int l,int r,int f1,int f2){
24     if(l+1>=r){
25         if(get_hash(f1,f1+r-1)==get_hash(f2,f2+r-1)) return r;
26         else return l;
27     }
28     int mid=(l+r)>>1;
29     if(get_hash(f1,f1+mid-1)==get_hash(f2,f2+mid-1)) return find(mid,r,f1,f2);
30     else return find(l,mid-1,f1,f2);
31 }
32 inline bool cmp(const S & x,const S & y){
33     int len1=len-x.pos+1,len2=len-y.pos+1;
34     int maxx=find(0,min(len1,len2)+1,x.pos,y.pos);
35     if(maxx==min(len1,len2)+1) return x.pos>y.pos;
36     else return s[x.pos+maxx]<s[y.pos+maxx];
37 }
38 int sa[maxn],rank[maxn],height[maxn];
39 int main(){
40     freopen("makedata.out","r",stdin);
41     freopen("mine.out","w",stdout);
42     scanf("%s",s+1); len=strlen(s+1);
43     base[0]=1; for(int i=1;i<=len;i++) base[i]=base[i-1]*BASE;
44     for(int i=1;i<=len;i++) hash[i]=hash[i-1]*BASE+s[i]-'a'+1;
45     for(int i=1;i<=len;i++) suf[i].pos=i;
46     sort(suf+1,suf+len+1,cmp);
47     for(int i=1;i<=len;i++){
48         rank[suf[i].pos]=i;
49         sa[i]=suf[i].pos;
50     }
51     for(int i=2;i<=len;i++){
52         int len1=len-sa[i-1]+1,len2=len-sa[i]+1;
53         height[i]=find(0,min(len1,len2),sa[i-1],sa[i]);
54     }
55     for(int i=1;i<=len;i++){
56         printf("%d %d\n",sa[i],height[i]);
57     }
58     return 0;
59 }

 

posted @ 2016-04-11 23:46  CXCXCXC  阅读(974)  评论(3编辑  收藏  举报