据说是后缀自动机裸题
然而,我还没有熟练掌握CE自动机,TLE自动机,RE自动机
并没有达到学习后缀自动机条件…………
后缀数组 :
二分答案,给height数组分组暴力判断
复杂度(nlogn)36ms
#include<set> #include<map> #include<ctime> #include<queue> #include<cmath> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define T 11111 using namespace std; char s[T]; int t1[T],t2[T],rank[T],cc[T],sa[T],height[T]; int n[6],st[9]={0,-1}; int len,m,L,R=T,ans; bool cmp(int *y,int a,int b,int k) { int a1=y[a],b1=y[b]; int a2=a+k>=len?-1:y[a+k]; int b2=b+k>=len?-1:y[b+k]; return a1==b1&&a2==b2; } void make_sa() { int *x=t1,*y=t2,m=333; for(int i=0;i<len;i++)++cc[x[i]=s[i]]; for(int i=1;i<m;i++)cc[i]+=cc[i-1]; for(int i=len-1;~i;i--)sa[--cc[x[i]]]=i; for(int k=1;k<len;k<<=1) { int p=0; for(int i=len-k;i<len;i++)y[p++]=i; for(int i=0;i<len;i++)if(sa[i]>=k)y[p++]=sa[i]-k; for(int i=0;i<m;i++)cc[i]=0; for(int i=0;i<len;i++)++cc[x[y[i]]]; for(int i=1;i<m;i++)cc[i]+=cc[i-1]; for(int i=len-1;~i;i--)sa[--cc[x[y[i]]]]=y[i]; swap(x,y),m=1,x[sa[0]]=0; for(int i=1;i<len;i++)x[sa[i]]=cmp(y,sa[i],sa[i-1],k)?m-1:m++; if(m>len)return; } } void make_height() { int k=0; for(int i=0;i<len;i++)rank[sa[i]]=i; for(int i=0;i<len;i++) { if(!rank[i])continue; int j=sa[rank[i]-1]; if(k)k--; while(s[i+k]==s[j+k])k++; height[rank[i]]=k; } } int search(int x) { if(s[x]=='#')return 0; for(int i=2;i<=m;i++) if(x<st[i])return i-1; return m; } bool jud(int x) { bool q[6]; int now=1,i; while(now<len) { if(height[now]>=x) { memset(q,0,sizeof(q)); q[search(sa[now-1])]=1; while(height[now]>=x&&now<len) { q[search(sa[now])]=1; now++; } for(i=1;i<=m;i++)if(!q[i])break; if(i>m)return 1; } else now++; } return 0; } int main() { scanf("%d",&m); for(int i=1;i<=m;i++) { scanf("%s",s+len); len+=(n[i]=strlen(s+len)); s[len]='#'; len++; st[i+1]=len-1; R=min(R,n[i]); } make_sa(); make_height(); while(L<=R) { int mid=L+R>>1; if(jud(mid))ans=mid,L=mid+1; else R=mid-1; } cout<<ans; return 0; }
字符串哈希
二分答案
求长度为当前答案长度的hash值存在hash表里
排序二分查找暴力判断
复杂度(nlog^2n)40ms
#include<set> #include<map> #include<ctime> #include<queue> #include<cmath> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define ll unsigned long long #define T 2111 using namespace std; char s[5][T]; ll P[T],f[5][T],h[T],hash[T]; ll Base=131; int top,n,L,R=T,ans,cnt; int l[5],mark[T]; int find(ll x) { int l=1,r=cnt; while(l<=r) { int mid=l+r>>1; if(hash[mid]==x)return mid; else if(hash[mid]>x)r=mid-1; else if(hash[mid]<x)l=mid+1; } return 0; } bool jud(int x) { cnt=top=0; for(int i=0;i+x<=l[0];i++) { h[++top]=f[0][i+x]-f[0][i]*P[x]; } sort(h+1,h+top+1); for(int i=1;i<=top;i++) if(h[i]!=h[i-1]) { hash[++cnt]=h[i]; } memset(mark,0,sizeof(mark)); for(int i=1;i<n;i++) { for(int j=0;j+x<=l[i];j++) { ll p=f[i][j+x]-f[i][j]*P[x]; int x=find(p); if(x!=0&&mark[x]==i-1)mark[x]=i; } } for(int i=1;i<=cnt;i++) if(mark[i]==n-1)return 1; return 0; } int main() { P[0]=1; for(int i=1;i<=2000;i++)P[i]=P[i-1]*Base; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%s",s[i]+1); l[i]=strlen(s[i]+1); f[i][0]=0; for(int j=1;j<=l[i];j++) { f[i][j]=f[i][j-1]*Base+s[i][j]; } R=min(l[i],R); } while(L<=R) { int mid=L+R>>1; if(jud(mid))ans=mid,L=mid+1; else R=mid-1; } cout<<ans; return 0; }