传送门:SPOJ - PHRASES(后缀数组+二分)

题意:给你n个字符串,找出一个最长的子串,他必须在每次字符串中都出现至少两次。

题解:被自己蠢哭...记录一下自己憨憨的操作,还一度质疑评测鸡(哭... 

首先是多个字符串的常规操作(目前写的题少,见到的都是这样)连成一个字符串,中间用不同的且没出现过的字符隔开。然后后缀数组求出sa数组和height数组,二分子串长度,用mx数组记录该串中的这个子串的起点最大值,mi数组记录最小值,如果所有串中的mx-mi都>=k说明这个长度可以。

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<queue>
  4 #include<iostream>
  5 #include<cmath>
  6 #include<cstring>
  7 using namespace std;
  8 
  9 //sa:字典序中排第i位的起始位置在str中第sa[i]  sa[1~n]为有效值
 10 
 11 //rnk:就是str第i个位置的后缀是在字典序排第几 rnk[0~n-1]为有效值
 12 
 13 //height:字典序排i和i-1的后缀的最长公共前缀  height[2~n]为有效值,第二个到最后一个
 14 
 15 const int INF=0x3f3f3f3f;
 16 const int maxn = 1e5+10;
 17 int wa[maxn],wb[maxn],wsf[maxn],wv[maxn],sa[maxn];
 18 int rnk[maxn],height[maxn],be[maxn];
 19 char s[maxn];
 20 int r[maxn],n,len,mx[maxn],mi[maxn];
 21 
 22 int cmp(int *r,int a,int b,int k)
 23 {
 24     return r[a]==r[b]&&r[a+k]==r[b+k];
 25 }
 26 
 27 void getsa(int *r,int *sa,int n,int m)//n为添加0后的总长
 28 {
 29     int i,j,p,*x=wa,*y=wb,*t;
 30     for(i=0; i<m; i++)  wsf[i]=0;
 31     for(i=0; i<=n; i++)  wsf[x[i]=r[i]]++;
 32     for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];
 33     for(i=n; i>=0; i--)  sa[--wsf[x[i]]]=i;
 34     p=1;
 35     j=1;
 36     for(; p<=n; j*=2,m=p){
 37         for(p=0,i=n+1-j; i<=n; i++)  y[p++]=i;
 38         for(i=0; i<=n; i++)  if(sa[i]>=j)  y[p++]=sa[i]-j;
 39         for(i=0; i<=n; i++)  wv[i]=x[y[i]];
 40         for(i=0; i<m; i++)  wsf[i]=0;
 41         for(i=0; i<=n; i++)  wsf[wv[i]]++;
 42         for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];
 43         for(i=n; i>=0; i--)  sa[--wsf[wv[i]]]=y[i];
 44         swap(x,y);
 45         x[sa[0]]=0;
 46         for(p=1,i=1; i<=n; i++)
 47             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;
 48     }
 49 }
 50 
 51 void getheight(int *r,int n)//n为添加0后的总长
 52 {
 53     int i,j,k=0;
 54     for(i=1; i<=n; i++)  rnk[sa[i]]=i;
 55     for(i=0; i<n; i++){
 56         if(k)
 57             k--;
 58         else
 59             k=0;
 60         j=sa[rnk[i]-1];
 61         while(r[i+k]==r[j+k])
 62             k++;
 63         height[rnk[i]]=k;
 64     }
 65 }
 66 
 67 bool check(int k)
 68 {
 69     for(int j=0;j<n;j++) mx[j]=-INF,mi[j]=INF;      //一开始忘记初始化
 70     for(int i=2;i<=len;i++){
 71         if(height[i]>=k){
 72             mx[be[sa[i]]]=max(mx[be[sa[i]]],sa[i]);
 73             mi[be[sa[i]]]=min(mi[be[sa[i]]],sa[i]);
 74             mx[be[sa[i-1]]]=max(mx[be[sa[i-1]]],sa[i-1]);
 75             mi[be[sa[i-1]]]=min(mi[be[sa[i-1]]],sa[i-1]);       //没眼睛写成了sa[i]
 76         }
 77         else{
 78             int j=0;
 79             for(j=0;j<n;j++) mx[j]=-INF,mi[j]=INF;
 80             mx[be[sa[i]]]=sa[i],mi[be[sa[i]]]=sa[i];
 81         }
 82         int j=0;
 83         for(j=0;j<n;j++){
 84             if(mx[j]-mi[j]<k) break;
 85         }
 86         if(j==n) return true;
 87     }
 88     return false;
 89 }
 90 
 91 int main()
 92 {
 93     ios::sync_with_stdio(false);
 94     cin.tie(0);
 95     cout.tie(0);
 96     int t;
 97     cin>>t;
 98     while(t--){
 99         cin>>n;
100         len=0;
101         for(int i=0;i<n;i++){
102             cin>>s+len;
103             int p=strlen(s+len);
104             for(int j=0;j<p;j++){
105                 r[j+len]=s[j+len]-'a'+1;
106                 be[len+j]=i;
107             }
108             len+=p;
109             if(i!=n-1){
110                 be[len]=i;
111                 r[len++]=i+100;
112             }
113         }
114         r[len]=0;
115         getsa(r,sa,len,200);
116         getheight(r,len);
117         int l=0,r=min(len,10000);
118         int ans=0;
119         while(l<=r){
120             int mid=l+r>>1;
121             if(check(mid)){
122                 ans=mid;
123                 l=mid+1;
124             }
125             else r=mid-1;
126         }
127         cout<<ans<<endl;
128     }
129     return 0;
130 }

 

SPOJ - PHRASES