题解:
后缀数组
把所有串连接起来
二分答案
代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> const int N=200005; typedef long long ll; using namespace std; char ch[N]; int str[N],l[N],mx[N],mn[N],in[N],k,wa[N],wb[N],wv[N],Ws[N],sa[N],Rank[N],height[N]; int cmp(int *r,int a,int b,int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } void da(const int *r,int *sa,int n,int m) { int *x=wa,*y=wb; for (int i=0;i<m;i++) Ws[i]=0; for (int i=0;i<n;i++) Ws[x[i]=r[i]]++; for (int i=1;i<m;i++) Ws[i]+=Ws[i-1]; for (int i=n-1;i>=0;i--) sa[--Ws[x[i]]]=i; for (int j=1,p=1;p<n;j*=2,m=p) { p=0; for (int i=n-j;i<n;i++) y[p++]=i; for (int i=0;i<n;i++) if (sa[i]>=j) y[p++]=sa[i]-j; for (int i=0;i<n;i++) wv[i]=x[y[i]]; for (int i=0;i<m;i++) Ws[i]=0; for (int i=0;i<n;i++) Ws[wv[i]]++; for (int i=1;i<m;i++) Ws[i]+=Ws[i-1]; for (int i=n-1;i>=0;i--) sa[--Ws[wv[i]]]=y[i]; swap(x,y);p=1;x[sa[0]]=0; for (int i=1;i<n;i++)x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } } void calheight(const int *r,int *sa,int n) { int j,k=0; for (int i=1;i<=n;i++) Rank[sa[i]]=i; for (int i=0;i<n;height[Rank[i++]]=k) for (k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++); } int pd(int mid,int n) { for (int i=0;i<k;i++){mx[i]=0;mn[i]=1e9;} for (int i=1;i<=n;i++) { if (height[i]<mid) { for (int j=0;j<k;j++) { mx[j]=0; mn[j]=1e9; } mx[in[sa[i]]]=sa[i]; mn[in[sa[i]]]=sa[i]; } else { mx[in[sa[i]]]=max(mx[in[sa[i]]],sa[i]); mn[in[sa[i]]]=min(mn[in[sa[i]]],sa[i]); mx[in[sa[i-1]]]=max(mx[in[sa[i-1]]],sa[i-1]); mn[in[sa[i-1]]]=min(mn[in[sa[i-1]]],sa[i-1]); int j; for (j=0;j<k;j++) if (mx[j]-mn[j]<mid)break; if (j==k) return 1; } } return 0; } int main() { int cnt=0,t; scanf("%d",&t); while (t--) { scanf("%d",&k); int n=0; for (int i=0;i<k;i++) { scanf("%s",ch); l[i]=strlen(ch); for (int j=n;j<n+l[i];j++) { str[j]=ch[j-n]-'a'+1; in[j]=i; } n+=l[i]+1; str[n-1]=27+i; } n--; str[n]=0; da(str,sa,n+1,27+k+5); calheight(str,sa,n); int l=0,r=10000; while (l<r) { int mid=(l+r+1)/2; if (pd(mid,n))l=mid; else r=mid-1; } printf("%d ",l); } return 0; }