POJ1226 Substrings(二分+后缀数组)
题意:给n个字符串,求最长的子串,满足它或它的逆置出现在所有的n个字符串中。
- 把n个字符串及其它们的逆置拼接,中间用不同字符隔开,并记录suffix(i)是属于哪个字符串的;
- 跑后缀数组计算height;
- 二分答案,height分组,看组里面是否都包含了n个字符串的后缀;
- 注意n=1的情况。。
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 using namespace std; 6 #define MAXN 22222 7 int wa[MAXN],wb[MAXN],wv[MAXN],ws[MAXN]; 8 int cmp(int *r,int a,int b,int l){ 9 return r[a]==r[b] && r[a+l]==r[b+l]; 10 } 11 int sa[MAXN],rank[MAXN],height[MAXN]; 12 void SA(int *r,int n,int m){ 13 int *x=wa,*y=wb; 14 15 for(int i=0; i<m; ++i) ws[i]=0; 16 for(int i=0; i<n; ++i) ++ws[x[i]=r[i]]; 17 for(int i=1; i<m; ++i) ws[i]+=ws[i-1]; 18 for(int i=n-1; i>=0; --i) sa[--ws[x[i]]]=i; 19 20 int p=1; 21 for(int j=1; p<n; j<<=1,m=p){ 22 p=0; 23 for(int i=n-j; i<n; ++i) y[p++]=i; 24 for(int i=0; i<n; ++i) if(sa[i]>=j) y[p++]=sa[i]-j; 25 for(int i=0; i<n; ++i) wv[i]=x[y[i]]; 26 for(int i=0; i<m; ++i) ws[i]=0; 27 for(int i=0; i<n; ++i) ++ws[wv[i]]; 28 for(int i=1; i<m; ++i) ws[i]+=ws[i-1]; 29 for(int i=n-1; i>=0; --i) sa[--ws[wv[i]]]=y[i]; 30 swap(x,y); x[sa[0]]=0; p=1; 31 for(int i=1; i<n; ++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 32 } 33 34 for(int i=1; i<n; ++i) rank[sa[i]]=i; 35 int k=0; 36 for(int i=0; i<n-1; height[rank[i++]]=k){ 37 if(k) --k; 38 for(int j=sa[rank[i]-1]; r[i+k]==r[j+k]; ++k); 39 } 40 } 41 42 int sn,n,r[MAXN],belong[MAXN]; 43 bool isok(int len){ 44 bool vis[111]={0}; int cnt=0; 45 for(int i=2; i<=n; ++i){ 46 if(height[i]>=len){ 47 if(!vis[belong[sa[i]]]){ 48 vis[belong[sa[i]]]=1; 49 ++cnt; 50 } 51 if(!vis[belong[sa[i-1]]]){ 52 vis[belong[sa[i-1]]]=1; 53 ++cnt; 54 } 55 if(cnt==sn) return 1; 56 }else{ 57 if(cnt==sn) return 1; 58 memset(vis,0,sizeof(vis)); 59 cnt=0; 60 } 61 } 62 return 0; 63 } 64 int main(){ 65 char str[111]; 66 int t; 67 scanf("%d",&t); 68 while(t--){ 69 n=0; 70 scanf("%d",&sn); 71 for(int i=0; i<sn; ++i){ 72 scanf("%s",str); 73 if(sn==1){ 74 printf("%d\n",strlen(str)); 75 break; 76 } 77 for(int j=0; str[j]; ++j){ 78 belong[n]=i; 79 r[n++]=str[j]; 80 } 81 r[n++]=127+(i<<1); 82 for(int j=strlen(str)-1; j>=0; --j){ 83 belong[n]=i; 84 r[n++]=str[j]; 85 } 86 r[n++]=127+(i<<1|1); 87 } 88 if(sn==1) continue; 89 r[--n]=0; 90 SA(r,n+1,333); 91 int l=0,r=100; 92 while(l<r){ 93 int mid=l+r+1>>1; 94 if(isok(mid)) l=mid; 95 else r=mid-1; 96 } 97 printf("%d\n",l); 98 } 99 return 0; 100 }