洛谷 P3808 【模板】AC自动机(简单版)洛谷 P3796 【模板】AC自动机(加强版)

https://www.cnblogs.com/gtarcoder/p/4820560.html

每个节点的后缀指针fail指针指向:

例如he,she,his,hers的例子(见蓝书P214):

7号点表示串his,将其头部去掉得到is但不存在该节点,再次将其头部去掉得到s,存在该节点,因此7号的后缀指针指向表示s的3号

5号点表示串she,将其头部去掉得到he,存在该节点,因此5号的后缀指针指向表示he的2号

从根节点到节点P可以得到一个字符串S,节点P的前缀指针定义为 指向树中出现过的S的最长后缀(不能等于S)

可以将trie上所有不存在的边u--(ch)-->v都补全为其fail指针指向的同类型边(f[u]--(ch)-->v'得到u--(ch)-->v')。(减少特判且方便递推)

每个节点的lst,与fail的区别在于,其指向的点表示的字符串一定是原来字符串集合中某一个完整的串(或空串),而fail则只要求原集合中某串的前缀即可

P3808中:由于只计算“出现过的”,所以某个算过贡献后要赋为0

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<queue>
  5 using namespace std;
  6 char *s[1001000],tttt[2000100],*sp=tttt,s2[1000100];
  7 int n;
  8 //namespace AC
  9 //{
 10 //    int ch[1001000][26],sum[1001000],f[1001000],root,mem,lst[1000100];
 11 //    void insert(char *x)
 12 //    {
 13 //        if(!root)    root=++mem;
 14 //        int now=root,u;
 15 //        for(;*x;x++)
 16 //        {
 17 //            u=*x-'a';
 18 //            if(!ch[now][u])    ch[now][u]=++mem;
 19 //            now=ch[now][u];
 20 //        }
 21 //        sum[now]++;
 22 //    }
 23 //    void build()
 24 //    {
 25 //        int c,t,u,v;
 26 //        queue<int> q;
 27 //        f[root]=root;
 28 //        for(c=0;c<26;c++)
 29 //        {
 30 //            u=ch[root][c];
 31 //            if(u)    {f[u]=root;q.push(u);lst[u]=root;}
 32 //        }
 33 //        while(!q.empty())
 34 //        {
 35 //            t=q.front();q.pop();
 36 //            for(c=0;c<26;c++)
 37 //            {
 38 //                u=ch[t][c];
 39 //                if(!u)    {ch[t][c]=ch[f[t]][c];continue;}
 40 //                q.push(u);
 41 //                v=f[t];
 42 //                while(v!=root&&!ch[v][c])    v=f[v];
 43 //                f[u]=ch[v][c];
 44 //                lst[u]=sum[u]?f[u]:lst[f[u]];
 45 //            }
 46 //        }
 47 //    }
 48 //    void search(char *x)
 49 //    {
 50 //        int j=root;
 51 //        for(;*x;x++)
 52 //        {
 53 //            c=*x-'a';
 54 //            if(sum[c])
 55 //        }
 56 //    }
 57 //}
 58 //注释掉的是root任意值的情况,未完成,以下程序认为root为0号点
 59 namespace AC
 60 {
 61     int ch[1001000][26],sum[1001000],f[1001000],mem,lst[1000100];
 62     void insert(char *x)
 63     {
 64         int now=0,u;
 65         for(;*x;x++)
 66         {
 67             u=*x-'a';
 68             if(!ch[now][u])    ch[now][u]=++mem;
 69             now=ch[now][u];
 70         }
 71         sum[now]++;
 72     }
 73     void build()
 74     {
 75         int c,t,u;
 76         queue<int> q;
 77         f[0]=0;
 78         for(c=0;c<26;c++)
 79         {
 80             u=ch[0][c];
 81             if(u)    {f[u]=0;q.push(u);lst[u]=0;}
 82         }
 83         while(!q.empty())
 84         {
 85             t=q.front();q.pop();
 86             for(c=0;c<26;c++)
 87             {
 88                 u=ch[t][c];
 89                 if(!u)    {ch[t][c]=ch[f[t]][c];continue;}
 90                 q.push(u);
 91                 f[u]=ch[f[t]][c];
 92                 lst[u]=sum[f[u]]?f[u]:lst[f[u]];
 93             }
 94         }
 95     }
 96     int ans;
 97     void get_ans(int j)
 98     {
 99         while(j)
100         {
101             ans+=sum[j];
102             sum[j]=0;
103             j=lst[j];
104         }
105     }
106     int count(char *x)
107     {
108         ans=0;
109         int j=0,c;
110         for(;*x;x++)
111         {
112             c=*x-'a';
113             j=ch[j][c];
114             get_ans(j);
115         }
116         return ans;
117     }
118 }
119 int main()
120 {
121     int i;
122     scanf("%d",&n);
123     for(i=1;i<=n;i++)
124     {
125         s[i]=sp;scanf("%s",s[i]);sp+=strlen(s[i])+1;
126         AC::insert(s[i]);
127     }
128     AC::build();
129     scanf("%s",s2);
130     printf("%d",AC::count(s2));
131     return 0;
132 }

P3796

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<queue>
  5 #include<vector>
  6 #include<map>
  7 #include<string>
  8 using namespace std;
  9 char *s[160],tttt[20000],*sp,s2[1000100];
 10 int n;
 11 namespace AC
 12 {
 13     int ch[20000][26],sum[20000],f[20000],mem,lst[20000],ans[20000];
 14     void clear()
 15     {
 16         int i,j;
 17         for(i=0;i<=mem;i++)
 18         {
 19             for(j=0;j<26;j++)    ch[i][j]=0;
 20             sum[i]=f[i]=lst[i]=ans[i]=0;
 21         }
 22         mem=0;
 23     }
 24     int insert(char *x)
 25     {
 26         int now=0,u;
 27         for(;*x;x++)
 28         {
 29             u=*x-'a';
 30             if(!ch[now][u])    ch[now][u]=++mem;
 31             now=ch[now][u];
 32         }
 33         sum[now]++;
 34         return now;
 35     }
 36     void build()
 37     {
 38         int c,t,u;
 39         queue<int> q;
 40         f[0]=0;
 41         for(c=0;c<26;c++)
 42         {
 43             u=ch[0][c];
 44             if(u)    {f[u]=0;q.push(u);lst[u]=0;}
 45         }
 46         while(!q.empty())
 47         {
 48             t=q.front();q.pop();
 49             for(c=0;c<26;c++)
 50             {
 51                 u=ch[t][c];
 52                 if(!u)    {ch[t][c]=ch[f[t]][c];continue;}
 53                 q.push(u);
 54                 f[u]=ch[f[t]][c];
 55                 lst[u]=sum[f[u]]?f[u]:lst[f[u]];
 56             }
 57         }
 58     }
 59     void get_ans(int j)
 60     {
 61         while(j)
 62         {
 63             ans[j]+=sum[j];
 64             j=lst[j];
 65         }
 66     }
 67     void work(char *x)
 68     {
 69         int j=0,c;
 70         for(;*x;x++)
 71         {
 72             c=*x-'a';
 73             j=ch[j][c];
 74             get_ans(j);
 75         }
 76     }
 77 }
 78 int pos[20000];
 79 int a1,anss;
 80 int main()
 81 {
 82     int i;
 83     while(1)
 84     {
 85         scanf("%d",&n);
 86         if(n==0)    break;
 87         AC::clear();
 88         sp=tttt;
 89         for(i=1;i<=n;i++)
 90         {
 91             s[i]=sp;scanf("%s",s[i]);sp+=strlen(s[i])+1;
 92             pos[i]=AC::insert(s[i]);
 93         }
 94         AC::build();
 95         scanf("%s",s2);
 96         AC::work(s2);a1=anss=0;
 97         for(i=1;i<=n;i++)
 98             if(AC::ans[pos[i]]>a1)
 99                 a1=AC::ans[pos[i]];
100         for(i=1;i<=n;i++)
101             if(AC::ans[pos[i]]==a1)
102                 anss++;
103         printf("%d\n",a1);
104         for(i=1;i<=n;i++)
105             if(AC::ans[pos[i]]==a1)
106                 printf("%s\n",s[i]);
107     }
108     return 0;
109 }
posted @ 2018-04-12 21:53  hehe_54321  阅读(321)  评论(0编辑  收藏  举报
AmazingCounters.com