zoukankan      html  css  js  c++  java
  • 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
    ",ans[pos[i]]);
        }return 0;
    }
    

      

  • 相关阅读:
    LAMP环境搭建博客
    PHP项目中经常用到的无限极分类函数
    在PHP项目中,每个类都要有对应的命名空间,为什么?
    一键解决docker pull hello-world的问题
    网盘10M速度下载-亿寻下载器
    《提问的智慧》
    idea出现 Error:(1, 1) java: 非法字符: 'ufeff'解决方式
    多线程的四种实现方式
    Java中的get()方法和set()方法
    Java构造器(构造方法/constructor)
  • 原文地址:https://www.cnblogs.com/forever97/p/hdu6096.html
Copyright © 2011-2022 走看看