这次的后缀数组写的成熟点,也好看点,以后生成后缀数组的话就用这里的build_sa()函数吧
rank[i]表示以i为起点的后缀在sa数组中的位置,height[i]则表示sa[i]和sa[i-1]的最长公共前缀的长度。
有一个定理:height[rank[i]]>=height[rank[i-1]-1,具体证明可以看刘汝佳的白书。
根据这个定理,每次for i=1 to n,每次根据height[rank[i-1]]求出height[rank[i]],减少比较次数。
sa[i]和sa[j]的最长公共前缀 = min{height[i+1],height[i+2]······,height[j] }(假设i<j)
还有,一定要记住求后缀数组时我的order数组不能直接更改,要当一轮顺序确定后再更改order的值,否则将出现很难察觉的错误。就因为这个,调程序到这么晚。。好苦。
对于这道题Codevs3160,直接将两个字符串合在一起,中间插入个特殊字符(两个字符串中都没有的),就再求后缀数组,再用后缀数组求最长公共前缀,再判断下每个前缀长度是否为合法答案即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<algorithm> 5 #include<cstring> 6 using namespace std; 7 int cmp_len=1,S_Len; 8 char S[300000]; 9 int order[500000],height[300000],rank[300000]; 10 struct A_Suffix{ 11 int st; 12 friend bool operator < (const A_Suffix a,const A_Suffix b){ 13 if(cmp_len==1) return S[a.st]<S[b.st]; 14 if(order[a.st]!=order[b.st]) return order[a.st]<order[b.st]; 15 return order[a.st+cmp_len/2]<order[b.st+cmp_len/2]; 16 } 17 friend bool operator ==(const A_Suffix a,const A_Suffix b){ 18 if(cmp_len==1) return S[a.st]==S[b.st]; 19 return (order[a.st]==order[b.st] && order[a.st+cmp_len/2]==order[b.st+cmp_len/2]); 20 } 21 }sa[500000]; 22 void build_sa(){ 23 int order2[500000]; 24 for(int i=0;i<S_Len;i++) sa[i]=((A_Suffix){i}); 25 while(1){ 26 sort(sa,sa+S_Len); 27 int k = order2[sa[0].st] = 1; 28 for(int i=1;i<S_Len;i++){ 29 if(!(sa[i]==sa[i-1])) k++; 30 order2[sa[i].st]=k; 31 } 32 for(int i=0;i<S_Len;i++) order[i]=order2[i]; 33 if(cmp_len>=S_Len) break; 34 cmp_len*=2; 35 } 36 } 37 void get_height(){ 38 int h=0; 39 for(int i=0;i<S_Len;i++) rank[sa[i].st]=i; 40 for(int i=0;i<S_Len;i++){ 41 if(h) h--; 42 if(rank[i]==0) {h=0;continue;} 43 int j=sa[rank[i]-1].st; 44 while(S[i+h]==S[j+h]) h++; //height[rank[i]]>=height[rank[i-1]]-1 45 height[rank[i]] = h; 46 } 47 } 48 49 int main(){ 50 scanf("%s",S); 51 int mid=strlen(S); 52 S[mid]='~'; 53 scanf("%s",S+strlen(S)); 54 S_Len=strlen(S); 55 build_sa();get_height(); 56 int ans=0; 57 for(int i=1;i<S_Len;i++){ 58 if(sa[i].st<mid && sa[i-1].st>mid) ans=max(ans,height[i]); 59 if(sa[i].st>mid && sa[i-1].st<mid) ans=max(ans,height[i]); 60 } 61 printf("%d\n",ans); 62 return 0; 63 }