AC自动机

#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<cstring>
#include <cctype>
using namespace std;
inline void read(int &x)
{
    x=0;int f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c<='9'&&c>='0'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    x*=f;
}
inline void print(int x)
{
    if(x<0){x=-x;putchar('-');}
    if(x>9) print(x/10);
    putchar(x%10+'0');
}
int n,sum;
char p[1000100];
int trie[500500][26];
int mk[500500];//标记次节点单词个数 
int faq[500500]; //失配指针 
queue<int>q;
int main()
{
   read(n);
   for(int i=1;i<=n;i++)
   {
           scanf("%s",p+1);
           int len=strlen(p+1),rt=0;
           for(int j=1;j<=len;j++)
           {
               int id=p[j]-'a';p[j]='\0';
               if(!trie[rt][id]) trie[rt][id]=++sum;
               rt=trie[rt][id];
        }
        mk[rt]++;
   }//建trie树 

   for(int i=0;i<=25;i++) if(trie[0][i]) faq[trie[0][i]]=0,q.push(trie[0][i]);
   //与根节点0相连的点的faq全指向0(作为模式串开头字母如果无法匹配只能到根节点上),并把存在的节点进队等待处理 
   while(!q.empty())
   {
        int u=q.front();q.pop();
        for(int i=0;i<=25;i++)
        {
            if(trie[u][i]) faq[trie[u][i]]=trie[faq[u]][i],q.push(trie[u][i]);
            //如果当前位置下有这个字母节点,则其失配指针指向当前位置的失配指针下的该节点;
            //若当前位置的失配指针下没有当前遍历的该字母节点,任不影响(为0,指向超级节点); 
            else trie[u][i]=trie[faq[u]][i];
            //当前位置下没有这个节点;就调到它失配指针所指向的节点下的此个字母节点; 
            //若为0,不影响,指向根节点;
        }
   }
       //造机原理:
       //若当前节点为A,其父节点为B,B的fail为C,那么C所代表的字符串一定是B的最长的后缀。
    //如果C有一个儿子D的字符与A的字符等同,那么显然D所代表的串(C加一个字符)就是A所代表的串(B加一个字符)的最长后缀。
    //如果C没有一个儿子,使其字符与A的字符等同呢?很简单,只需要再访问C的fail就行了。
    //如此反复,直到A的最长后缀找到,或者A的fail指向根节点为止。 
    scanf("%s",p+1);
    int len=strlen(p+1),rt=0,ans=0;
    for(int i=1;i<=len;i++)
    {
        rt=trie[rt][p[i]-'a'];//当前位置的下一个节点位置;
        for(int j=rt;j&&mk[j];j=faq[j]) ans+=mk[j],mk[j]=0;
        //当此节点存在同时其单词个数未被统计;
        //将答案加上所搜索的字符串中所包含的该单词数 ; 
        //标记已经统计
        //直接将位置指向其失配指针的位置(节约时间); 
    }
    printf("%d\n",ans);
    return 0;
}
全部评论

相关推荐

一个菜鸡罢了:哥们,感觉你的简历还是有点问题的,我提几点建议,看看能不能提供一点帮助 1. ”新余学院“别加粗,课程不清楚是否有必要写,感觉版面不如拿来写一下做过的事情,教育经历是你的弱势就尽量少写 2. “干部及社团经历”和“自我评价”删掉 3. 论文后面的“录用”和“小修”啥的都删掉,默认全录用,问了再说,反正小修毕业前肯定能发出来 4. 工作经验和研究成果没有体现你的个人贡献,着重包装一下个人贡献
点赞 评论 收藏
分享
10-30 10:16
南京大学 Java
永远的鹅孝子:给南大✌️跪了
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务