题目大意是说给你一些字符串,然后让你求出其中最长的在每个字符串中出现不重复2次的长度。
这个题是罗大神关于后缀数组论文的倒数第二题,思路上面都有,其实和多字符串问题处理方式差不多。对n个字符串拼接成一个字符串,相邻字符串用不同一个没有出现过的字符隔开,然后跑一次后缀数组。
然后采用二分的方法计算答案值,需要注意的是,每次判断的时候不仅要增加对不重复的检测,也要对是否每个字符串都包含这样的相同字符串进行检测。
代码:
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int maxn=1e5+100; const int maxm=10100; int n,m,mo,r[maxn],wa[maxn],wb[maxn],wv[maxn],wu[maxn],rank[maxn],sa[maxn],height[maxn],bel[maxn],maxi[11],mini[11]; char str[maxm]; bool vis[11]; int cmp(int *r,int a,int b,int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } void da(int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i=0;i<m;i++) wu[i]=0; for(i=0;i<n;i++) wu[x[i]=r[i]]++; for(i=1;i<m;i++) wu[i]+=wu[i-1]; for(i=n-1;i>=0;i--) sa[--wu[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++) wu[i]=0; for(i=0;i<n;i++) wu[wv[i]]++; for(i=1;i<m;i++) wu[i]+=wu[i-1]; for(i=n-1;i>=0;i--) sa[--wu[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++; } } void calheight(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--:k=0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++); } bool check(int val) { memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) { if(height[i]<val) { bool flag=0; for(int j=1;j<=m;j++) { if(!vis[j]||maxi[j]-mini[j]<val) { flag=1; break; } } if(!flag) return true; memset(vis,0,sizeof(vis)); vis[bel[sa[i]]]=1; mini[bel[sa[i]]]=maxi[bel[sa[i]]]=sa[i]; } else { if(!vis[bel[sa[i]]]) { mini[bel[sa[i]]]=maxi[bel[sa[i]]]=sa[i]; vis[bel[sa[i]]]=1; } maxi[bel[sa[i]]]=max(maxi[bel[sa[i]]],sa[i]); mini[bel[sa[i]]]=min(mini[bel[sa[i]]],sa[i]); } } for(int i=1;i<=m;i++) if(!vis[i]||maxi[i]-mini[i]<val) return false; return true; } int main() { int T; scanf("%d",&T); while(T--) { memset(bel,0,sizeof(bel)); scanf("%d",&m); n=0; mo=300; for(int i=1;i<=m;i++) { scanf("%s",str); int len=strlen(str); for(int j=0;j<len;j++) { r[n]=str[j]; bel[n++]=i; } r[n]=mo++; bel[n++]=0; } r[--n]=0; da(n+1,500); calheight(n); int l=1,r=n,ans=0; while(l<=r) { int mid=(l+r)>>1; if(check(mid)) { ans=mid; l=mid+1; } else r=mid-1; } printf("%d\n",ans); } return 0; }