给出几个由小写字母构成的单词,求它们最长的公共子串的长度。n<=5,maxlen<=2000.
预处理出每个串的哈希值
二分答案len,前4个串的所有长为len的子串全部用map存,再最后一个串跑,看是否在前面全部出现.
常数略大,但是数据比较小没问题
#include <bits/stdc++.h> #define ull unsigned long long #define clr(x,i) memset(x,i,sizeof(x)) using namespace std; const int N=2005; const ull seed=173; char str[6][N]; int n,len[6],a[6][N]; ull h[6][N],pw[N]; map<int,ull> mp[6]; inline ull geth(int k,int l,int r) { return h[k][r]-h[k][l-1]*pw[r-l+1]; } bool check(int now) { for(int i=1;i<=n;i++) mp[i].clear(); for(int i=1;i<n;i++) { for(int j=1;j+now-1<=len[i];j++){ ull ret=geth(i,j,j+now-1); mp[i][ret]=1; } } for(int i=1;i+now-1<=len[n];i++) { ull x=geth(n,i,i+now-1); bool flag=1; for(int j=1;j<n;j++) if(!mp[j][x])flag=0; if(flag)return true; } return false; } void solve() { int l=1,r=len[1],mid,ans=0; for(int i=1;i<=n;i++)r=max(r,len[i]); while(l<=r) { mid=(l+r)>>1; if(check(mid)) ans=mid,l=mid+1; else r=mid-1; } printf("%d",ans); } int main() { scanf("%d",&n); if(n==1){ printf("0");return 0; } for(int i=1;i<=n;i++){ scanf("%s",str[i]+1);len[i]=strlen(str[i]+1); for(int j=1;j<=len[i];j++) a[i][j]=str[i][j]-'a'+1; } pw[0]=1; for(int i=1;i<=2000;i++)pw[i]=pw[i-1]*seed; for(int i=1;i<=n;i++) for(int j=1;j<=len[i];j++) h[i][j]=h[i][j-1]*seed+a[i][j]; solve(); return 0; }这个好像是后缀自动机的模板题,以后来补。。