HDU 6138 Fleet of the Eternal Throne(AC自动机)

 

【题目链接】 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\n",ans);
        }
    }return 0;
}

 

posted @ 2017-08-21 12:25  forever97  阅读(356)  评论(0编辑  收藏  举报