题目描述:
给定n个字符串,求出现或反转后出现在每个字符串中的最长子串。
算法标签:后缀数组
以下代码:
#include<bits/stdc++.h> #define il inline #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=3e4+5;char a[N]; int n,l,rk[N],sa[N],x[N],y[N],height[N],c[N],pos[N],t,mn[N][20],ans,s[N]; il int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return f*x;} il void getsa(){ int m=202+t*2; for(int i=1;i<=m;i++)c[i]=0; for(int i=1;i<=n;i++)c[x[i]=s[i]]++; for(int i=2;i<=m;i++)c[i]+=c[i-1]; for(int i=n;i;i--)sa[c[x[i]]--]=i; for(int k=1;k<=n;k<<=1){ int num=0; for(int i=n-k+1;i<=n;i++)y[++num]=i; for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k; for(int i=1;i<=m;i++)c[i]=0; for(int i=1;i<=n;i++)c[x[i]]++; for(int i=2;i<=m;i++)c[i]+=c[i-1]; for(int i=n;i;i--){ sa[c[x[y[i]]]--]=y[i],y[i]=0; } swap(x,y);num=1;x[sa[1]]=1; for(int i=2;i<=n;i++) x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num; if(num==n)break;m=num; } for(int i=1;i<=n;i++)rk[sa[i]]=i; } il void geth(){ int k=0; for(int i=1;i<=n;i++){ if(rk[i]==1)continue; if(k)k--;int j=sa[rk[i]-1]; while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++; height[rk[i]]=k; } } il void init(){ for(int i=1;i<=n;i++)mn[i][0]=height[i]; for(int j=1;(1<<j)<=n;j++)for(int i=1;i+(1<<j)-1<=n;i++) mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]); } il int rmq(int l,int r){ int k=0;while((1<<(k+1))<=r-l+1)k++; return min(mn[l][k],mn[r-(1<<k)+1][k]); } il int lcp(int l,int r){return rmq(l+1,r);} int main() { int T=read();while(T--){ t=read();n=0; for(int i=1;i<=t;i++){ scanf(" %s",a+1);int l=strlen(a+1); for(int j=1;j<=l;j++)s[++n]=a[j],pos[n]=i; s[++n]=199+i*2; for(int j=l;j;j--)s[++n]=a[j],pos[n]=i; s[++n]=200+i*2; } getsa();geth();init();int r=1,num=0;ans=0; for(int i=1;i<=t;i++)c[i]=0; for(int i=1;i<=n;i++){ while(num<t&&r<=n){ c[pos[sa[r]]]++;if(c[pos[sa[r]]]==1&&pos[sa[r]]!=0)num++;r++; } if(num<t)break; ans=max(ans,lcp(i,r-1)); c[pos[sa[i]]]--;if(c[pos[sa[i]]]==0&&pos[sa[i]]!=0)num--; } printf("%d ",ans); } return 0; }