HDU 6096 String(AC自动机)

 

【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=6096

 

【题目大意】

  给出一些字符串,给出前缀后缀模式询问,问有多少字符串符合该模式

 

【题解】

  我们将字符串变为双倍,在中间增加拼接符,
  对于每个前后缀模式,我们将其处理为[后缀+拼接符+前缀]的形式,
  那么原题等价于统计前后缀模式在多少个字符串中出现,
  我们用所有的前后缀模式建立AC自动机,用每个字符串在AC自动机上跑匹配,
  最后统计fail链前继累加和即可。 

  对于前缀和后缀不能重叠的条件,
  我们记录串长+1作为其搜索长度,比如abcde#abcde我们用长度为6来记录,
  这样子就不会出现匹配到cde#abc这样子的情况了

 

【代码】

#include <cstdio>
#include <cstring>
using namespace std;
const int N=1200010;
namespace AC_DFA{
    const int Csize=27; 
    int tot,son[N][Csize],sum[N],fail[N],q[N],ans[N],dph[N],match[N];
    void Initialize(){
        memset(sum,0,sizeof(int)*(tot+1));
        memset(dph,0,sizeof(int)*(tot+1)); 
        memset(ans,0,sizeof(int)*(tot+1));
        memset(match,0,sizeof(int)*(tot+1)); 
        memset(fail,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];
            match[son[x][i]]=sum[son[x][i]]?son[x][i]:match[fail[son[x][i]]];
        }else son[x][i]=son[fail[x]][i];
    }
    void Search(char *s,int len){
        for(int l=strlen(s),i=0,x=0,w;i<l;i++){
            x=son[x][Tr(s[i])];
            while(dph[x]>len)x=fail[x];
            ans[match[x]]++;
        }
    }
    int d[N],st[N];
    void Solve(){
        int k=0;
        memset(d,0,sizeof(int)*(tot+1));
        for(int i=1;i<=tot;i++)d[fail[i]]++;
        for(int i=1;i<=tot;i++)if(!d[i])st[k++]=i;
        for(int i=0;i<k;i++){
            int j=fail[st[i]];
            ans[j]+=ans[st[i]];
            if(!--d[j])st[k++]=j;
        }
    }
}
int len[100010],pos[100010];
char ss[N],t1[N],t2[N];
char *s[100010];
using namespace AC_DFA;
int main(){
    int T,n,q;
    scanf("%d",&T);
    while(T--){
        Initialize();
        scanf("%d%d",&n,&q);
        for(int i=0,j=0;i<n;i++){
            s[i]=ss+j;
            scanf("%s",s[i]);
            len[i]=strlen(s[i])+1;
            j+=len[i];
            strcpy(ss+j,s[i]);
            ss[j-1]='z'+1;
            j+=len[i];
        }
        for(int i=0;i<q;i++){
            t1[0]='z'+1;
            scanf("%s%s",t1+1,t2);
            strcat(t2,t1); 
            pos[i]=Insert(t2);
        }MakeFail();
        for(int i=0;i<n;i++)Search(s[i],len[i]);
        Solve();
        for(int i=0;i<q;i++)printf("%d\n",ans[pos[i]]);
    }return 0;
}

  

posted @ 2017-08-11 14:57  forever97  阅读(830)  评论(0编辑  收藏  举报