LA 4670 Dominating Patterns AC自动机

题目链接

https://vjudge.net/problem/UVALive-4670

题意

有n个由小写字母组成的字符串和一个文本串T,你的任务是找出哪些字符串在文本中出现的次数最多。输出最多出现的次数,接下来每行包含一个出现次数最多的字符串,按照输入顺序排列。

解题

将n个字符串插入字典树,然后通过bfs寻找后缀结点构建ac自动机。
将文本串与ac自动机去匹配,统计每个字符出现的次数ans[i]。
然后遍历ans去找最多次数sum。用sum去与ans[i]比较,相等的话就输出第i个字符串。

一开始用了三个map去存,果断T了。后来注意到只需将尾结点编号与字符串编号做个映射就好了。

AC代码

#include <bits/stdc++.h>
using namespace std;

int sum;
int ans[200];
int num[155*70];

struct trie
{
    int sz,ch[155*70][26],ed[155*70],fail[155*70];
    void init()
    {
        sz=0;
        memset(ch[0],0,sizeof(ch[0]));
        memset(ans,0,sizeof(ans));
    }
    void insert(char *s,int id)
    {
        int len=strlen(s),p=0;
        for(int i=0;i<len;i++)
        {
            int c=s[i]-'a';
            if(!ch[p][c])
            {
                ch[p][c]=++sz;
                memset(ch[sz],0,sizeof(ch[sz]));
                ed[sz]=0;
            }
            p=ch[p][c];
        }
        ed[p]++;
        num[p]=id;
    }
    void build()
    {
        queue<int> que;
        int p=0;
        for(int i=0;i<26;i++)
        {
            int &c=ch[p][i];
            if(c) fail[c]=0,que.push(c);
            else c=0;
        }
        while(!que.empty())
        {
            int now=que.front();que.pop();
            int nxt=fail[now];
            for(int i=0;i<26;i++)
            {
                int &c=ch[now][i];
                if(c) fail[c]=ch[nxt][i],que.push(c);
                else c=ch[nxt][i];
            }
        }
    }
    void solve(char *s)
    {
        int len=strlen(s),p=0;
        sum=0;
        for(int i=0;i<len;i++)
        {
            int c=s[i]-'a';
            p=ch[p][c];
            int tmp=p;
            while(tmp)
            {
                ans[num[tmp]]+=ed[tmp];
                sum=max(sum,ans[num[tmp]]);
                tmp=fail[tmp];
            }
        }
    }
}ac;
const int maxn=1e6+7;
char str[maxn];
char P[200][80];
int main()
{
    int n;
    while(~scanf("%d",&n),n)
    {
        ac.init();
        for(int i=1;i<=n;i++)
        {
            char s[80];
            scanf("%s",P[i]);
            ac.insert(P[i],i);
        }
        ac.build();
        scanf("%s",str);
        ac.solve(str);
        printf("%d\n",sum);
        for(int i=1;i<=n;i++)
        {
            if(ans[i]==sum) printf("%s\n",P[i]);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37685156/article/details/81503394
LA