【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=6138
【题目大意】
给出一些串,询问第x个串和第y个串的公共子串,
同时要求该公共子串为某个串的前缀。求最长符合要求的答案
【题解】
我们对所有串构建AC自动机,将两个询问串之一在AC自动机上mark所有的匹配位置
另一个串在mark的地方寻找最长匹配即可
【代码】
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=100010; int ans; namespace AC_DFA{ const int Csize=27; int tot,son[N][Csize],sum[N],fail[N],q[N],dph[N],vis[N]; void Initialize(){ memset(dph,0,sizeof(int)*(tot+1)); memset(fail,0,sizeof(int)*(tot+1)); memset(sum,0,sizeof(int)*(tot+1)); for(int i=0;i<=tot;i++)for(int j=0;j<Csize;j++)son[i][j]=0; tot=0; fail[0]=-1; } inline int Tr(char ch){return ch-'a';} int Insert(char *s){ int x=0; for(int l=strlen(s),i=0,w;i<l;i++){ if(!son[x][w=Tr(s[i])]){ son[x][w]=++tot; dph[tot]=i+1; }x=son[x][w]; }sum[x]++; return x; } void MakeFail(){ int h=1,t=0,i,j,x; for(i=0;i<Csize;i++)if(son[0][i])q[++t]=son[0][i]; while(h<=t)for(x=q[h++],i=0;i<Csize;i++) if(son[x][i]){ fail[son[x][i]]=son[fail[x]][i],q[++t]=son[x][i]; }else son[x][i]=son[fail[x]][i]; } void Cal(char *s){ memset(vis,0,sizeof(vis)); for(int l=strlen(s),i=0,x=0,w;i<l;i++){ while(!son[x][Tr(s[i])])x=fail[x]; x=son[x][Tr(s[i])]; for(int j=x;j;j=fail[j])vis[j]=1; } } void Find(char *s){ for(int l=strlen(s),i=0,x=0,w;i<l;i++){ while(!son[x][Tr(s[i])])x=fail[x]; x=son[x][Tr(s[i])]; for(int j=x;j;j=fail[j])if(vis[j])ans=max(ans,dph[j]); } } } char s[110][N]; int T,n; int main(){ scanf("%d",&T); while(T--){ scanf("%d",&n); using namespace AC_DFA; Initialize(); for(int i=1;i<=n;i++){ scanf("%s",s[i]); Insert(s[i]); }int q; MakeFail(); scanf("%d",&q); while(q--){ int x,y; ans=0; scanf("%d%d",&x,&y); Cal(s[x]); Find(s[y]); printf("%d ",ans); } }return 0; }