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 }

 

posted @ 2016-02-28 16:34  WABoss  阅读(239)  评论(0编辑  收藏  举报