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