题意:找出一个字符串中至少重复出现两次的字串的个数(重复出现时不能重叠)。
后缀数组
枚举字串长度h,对于每一次的h,利用height数组,找出连续的height大于等于h的里面最左端和最右端得为之l和r。
如果l+h-1<r的话,说明没有重叠,答案加1.
1 #include<algorithm> 2 #include<cstdlib> 3 #include<cstring> 4 #include<cstdio> 5 #include<cmath> 6 using namespace std; 7 8 #define N 1010 9 10 int wa[N],wb[N],ws[N],wv[N]; 11 int sa[N],rank1[N],height[N]; 12 int r[N]; 13 14 char s[N]; 15 16 int n,ans; 17 18 int cmp(int *r,int a,int b,int l) 19 { 20 return r[a]==r[b] && r[a+l]==r[b+l]; 21 } 22 23 void da(int *r,int n,int m) 24 { 25 int i,j,p,*x=wa,*y=wb,*t; 26 for (i=0;i<m;i++) ws[i]=0; 27 for (i=0;i<n;i++) ws[x[i]=r[i]]++; 28 for (i=1;i<m;i++) ws[i]+=ws[i-1]; 29 for (i=n-1;i>=0;i--) sa[--ws[x[i]]]=i; 30 for (j=1,p=1;p<n;j<<=1,m=p) 31 { 32 for (p=0,i=n-j;i<n;i++) y[p++]=i; 33 for (i=0;i<n;i++) if (sa[i]>=j) y[p++]=sa[i]-j; 34 for (i=0;i<n;i++) wv[i]=x[y[i]]; 35 for (i=0;i<m;i++) ws[i]=0; 36 for (i=0;i<n;i++) ws[wv[i]]++; 37 for (i=1;i<m;i++) ws[i]+=ws[i-1]; 38 for (i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i]; 39 for (t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++) 40 x[sa[i]]=cmp(y,sa[i-1],sa[i],j) ? p-1 : p++; 41 } 42 return ; 43 } 44 45 void calheight(int *r,int n) 46 { 47 int i,j,k=0; 48 for (i=1;i<=n;i++) rank1[sa[i]]=i; 49 for (i=0;i<n;height[rank1[i++]]=k) 50 for (k ? k-- : 0,j=sa[rank1[i]-1];r[i+k]==r[j+k];k++); 51 return ; 52 } 53 54 int main() 55 { 56 while (scanf("%s",s)!=EOF && s[0]!='#') 57 { 58 ans=0; 59 n=strlen(s); 60 for (int i=0;i<n;i++) 61 r[i]=s[i]-'a'+2; 62 r[n]=0; 63 da(r,n+1,30); 64 calheight(r,n); 65 for (int i=1;i<=n/2;i++) 66 { 67 int l=n+1,r=0; 68 for (int j=2;j<=n;j++) 69 { 70 if (height[j]>=i) 71 { 72 r=max(r,sa[j-1]); 73 r=max(r,sa[j]); 74 l=min(l,sa[j-1]); 75 l=min(l,sa[j]); 76 } 77 else 78 { 79 if (r-l>=i) 80 ans++; 81 r=0; 82 l=n+1; 83 } 84 } 85 if (r-l>=i) 86 ans++; 87 } 88 printf("%d ",ans); 89 } 90 return 0; 91 }