后缀数组是处理字符串问题的有力工具。
其中有些变量需要说明下,sa[i]是排名为第i的后缀所在字符串中的位置。height[i]表示sa[i-1]和sa[i]两个后缀的最长公共前缀,即相邻排名两串的公共前缀。
LCP(i,j)也就是后缀数组中第i个和第j个后缀的最长公共前缀的长度
例题,uva 12506,求区别所有字符串的最少字符数
具体见代码:
View Code
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<climits> using namespace std; #define maxn 1000009 int wa[maxn],wb[maxn],wv[maxn],wsm[maxn],sa[maxn],Len[maxn],pos[maxn]; int cmp(int *r,int a,int b,int l) {return r[a]==r[b]&&r[a+l]==r[b+l];} void da(int *r,int *sa,int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i=0;i<m;i++) wsm[i]=0; for(i=0;i<n;i++) wsm[x[i]=r[i]]++; for(i=1;i<m;i++) wsm[i]+=wsm[i-1]; for(i=n-1;i>=0;i--) sa[--wsm[x[i]]]=i; for(j=1,p=1;p<n;j*=2,m=p) { for(p=0,i=n-j;i<n;i++) y[p++]=i; for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; for(i=0;i<n;i++) wv[i]=x[y[i]]; for(i=0;i<m;i++) wsm[i]=0; for(i=0;i<n;i++) wsm[wv[i]]++; for(i=1;i<m;i++) wsm[i]+=wsm[i-1]; for(i=n-1;i>=0;i--) sa[--wsm[wv[i]]]=y[i]; for(t=x,x=y,y=t,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++; } return; } int Rank[maxn],height[maxn]; void calheight(int *r,int *sa,int n) { int i,j,k=0; for(i=1;i<=n;i++) Rank[sa[i]]=i; for(i=0;i<n;height[Rank[i++]]=k) for(k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++); return; } int RMQ[maxn]; int mm[maxn]; int best[20][maxn]; void initRMQ(int n) { for(int i = 0; i <= n; i++) RMQ[i] = height[i]; int i,j,a,b; for(mm[0]=-1,i=1;i<=n;i++) mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1]; for(i=1;i<=n;i++) best[0][i]=i; for(i=1;i<=mm[n];i++) for(j=1;j<=n+1-(1<<i);j++) { a=best[i-1][j]; b=best[i-1][j+(1<<(i-1))]; if(RMQ[a]<RMQ[b]) best[i][j]=a; else best[i][j]=b; } return; } int askRMQ(int a,int b) { int t; t=mm[b-a+1];b-=(1<<t)-1; a=best[t][a];b=best[t][b]; return RMQ[a]<RMQ[b]?a:b; } int lcp(int a,int b) { int t; a=Rank[a];b=Rank[b]; if(a>b) {t=a;a=b;b=t;} return height[askRMQ(a+1,b)]; } char ss[maxn]; int ans[maxn]; int main(){ int cas; scanf("%d",&cas); for(int tcase=1;tcase<=cas;tcase++){ int n; scanf("%d",&n); int cnt = 0; for(int i=1;i<=n;i++){ scanf("%s",ss); int len = strlen(ss); pos[i] = cnt; Len[i] = len; for(int j=0;j<len;j++){ ans[cnt++] = ss[j]-'a'+500; } } ans[cnt]=0; da(ans,sa,cnt+1,1280); calheight(ans,sa,cnt); initRMQ(cnt); int was = 0; for(int i=1;i<=n;i++){ int ans1 = 0; for(int j=1;j<=n;j++){ if(i==j) continue; ans1 = max(ans1,lcp(pos[i],pos[j])); } was += ans1+1; } printf("%d\n",was); } return 0; }