题目链接:http://www.spoj.pl/problems/PHRASES/
题目思路:二分答案,然后分组,看一组中是否包含所有字符串,且每个字符串出现两次及两次以上,然后距离差大于等于k。
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<string> #include<queue> #include<algorithm> #include<vector> #include<stack> #include<list> #include<iostream> #include<map> using namespace std; #define inf 0x3f3f3f3f #define M 110000 int max(int a,int b) { return a>b?a:b; } int min(int a,int b) { return a<b?a:b; } int rank[M],sa[M],height[M]; int ta[M],tb[M],tv[M],ts[M],r[M],pos[M]; bool cmp(int *y,int a,int b,int l) { return y[a]==y[b]&&y[a+l]==y[b+l]; } void da(int n,int m) { int i,j,p,*x=ta,*y=tb; for(i=0;i<m;i++) ts[i]=0; for(i=0;i<n;i++) ts[x[i]=r[i]]++; for(i=1;i<m;i++) ts[i]+=ts[i-1]; for(i=n-1;i>=0;i--) sa[--ts[x[i]]]=i; for(j=1,p=1;p<n;j*=2,m=p) { p=0; for(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<m;i++) ts[i]=0; for(i=0;i<n;i++) tv[i]=x[y[i]]; for(i=0;i<n;i++) ts[tv[i]]++; for(i=1;i<m;i++) ts[i]+=ts[i-1]; for(i=n-1;i>=0;i--) sa[--ts[tv[i]]]=y[i]; swap(x,y); x[sa[0]]=0; p=1; for(i=1;i<n;i++) { if(cmp(y,sa[i-1],sa[i],j)) x[sa[i]]=p-1; else x[sa[i]]=p++; } } } void calh(int n) { int i,k,tmp; for(i=1;i<=n;i++) rank[sa[i]]=i; k=0; for(i=0;i<n;i++) { tmp=sa[rank[i]-1]; for(;r[i+k]==r[tmp+k];k++) ; height[rank[i]]=k; k?--k:0; } } int check(int tp,int n,int k) { int i,j,tmp,num=0,mi[12],mx[12]; for(i=0;i<tp;i++) { mi[i]=-1,mx[i]=-1; } tmp=pos[sa[1]]; mi[tmp]=mx[tmp]=sa[1]; for(i=2;i<=n;i++) { if(height[i]<k) { num=0; for(j=0;j<tp;j++) { if(mi[j]!=-1&&mx[j]-mi[j]>=k) num++; mi[j]=mx[j]=-1; } if(num==tp) return 1; tmp=pos[sa[i]]; mi[tmp]=mx[tmp]=sa[i]; } else { tmp=pos[sa[i]]; if(mi[tmp]==-1) mi[tmp]=mx[tmp]=sa[i]; else { mi[tmp]=min(mi[tmp],sa[i]); mx[tmp]=max(mx[tmp],sa[i]); } } } num=0; for(j=0;j<tp;j++) { if(mi[j]!=-1&&mx[j]-mi[j]>=k) num++; mi[j]=mx[j]=-1; } if(num==tp) return 1; return 0; } void getans(int l,int r,int n,int tp) { int mid; while(l<=r) { mid=(l+r)>>1; if(check(tp,n,mid)) l=mid+1; else r=mid-1; } printf("%d\n",r); } char s[M]; int main() { int t,i,j,n,len,mi,tp; scanf("%d",&t); while(t--) { scanf("%d",&tp); n=0; mi=inf; for(i=0;i<tp;i++) { scanf("%s",s); len=strlen(s); mi=min(mi,len); for(j=n;j<n+len;j++) { r[j]=s[j-n];pos[j]=i; } r[n+len]=129+i; pos[n+len]=i; n+=len+1; } n--;r[n]=0; da(n+1,200); calh(n); getans(1,mi,n,tp); } }