COGS 1913. AC自动机

★★   输入文件:ACautomata.in   输出文件:ACautomata.out   简单对比
时间限制:1 s   内存限制:128 MB

【题目描述】

对,这就是裸的AC自动机。

要求:在规定时间内统计出模版字符串在文本中出现的次数。

【输入格式】

第一行:模版字符串的个数N(N<=10)

第2->N+1行:N个字符串。(每个模版字符串的长度<=50)

第N+2行:一行很长的字符串。长度小于1e8。(使用AC自动机能在1s内计算出)

数据已加强

原前rk10复杂度不对的做法全部被卡tle(逃

by rapiz 2017/3/11

【输出格式】

共N行,每行输出一个模版及出现的次数。(之间有一个空格,按照输入顺序输出)

【样例输入】

 

4

hers

her

his

she

shershisher

 

【样例输出】

 

hers 1

her 2

his 1

she 2

 

【提示】

所有字母均为小写

所给模版不会重复

【来源】

 

AC自动机模板 

屠龙宝刀点击就送

1:不明觉厉的什么统计方法。。AC自动机

2:自己写的方法 List算法+AC自动机 

Q:什么是list算法?

A:list算法 O(1)判断 O(1)时间内解决问题。

Q:能说的通俗点吗?

A:打表。

#include <cstring>
#include <string>
#include <cstdio>
struct node
{
    int pos,id;
    node * next[27],*fail;
    node()
    {
        for(int i=0;i<26;i++) next[i]=NULL;
        fail=NULL;
        id=pos=0;
    }
}*root;
int Q[11],n,size,ans[1005];
void ins(int num,char *a)
{
    node *p=root;
    for(char *q=a;*q;q++)
    {
        int id=*q-'a';
        if(p->next[id]==NULL)
        {
            p->next[id]=new node;
            p->next[id]->id=++size;
        }
        p=p->next[id];
    }
    Q[num]=p->id;
    p->pos=num;
}
node * q[1005];
int head=0,tail=-1;
char word[11][51];
void build()
{
    for(int i=0;i<26;i++)
    {
        if(root->next[i])
        {
            root->next[i]->fail=root;
            q[++tail]=root->next[i];
        }
        else root->next[i]=root;
    }
    while(head<=tail)
    {
        node * now=q[head++];
        for(int i=0;i<26;i++)
        {
            if(now->next[i]!=NULL)
            {
                now->next[i]->fail=now->fail->next[i];
                q[++tail]=now->next[i];
            }
            else now->next[i]=now->fail->next[i];
        }
    }
}
void query(char *a)
{
    node * p=root;
    int len=strlen(a);
    for(int i=0;i<len;i++ )
    {
        int id=a[i]-'a';
        p=p->next[id];
        ans[p->id]++;
    }
    for(int i=tail;i>=0;i--)
    {
        p=q[i];
        ans[p->fail->id]+=ans[p->id];
    }
    for(int i=1;i<=n;i++) printf("%s %d\n",word[i],ans[Q[i]]); 
}
char key[100000001];
int Main()
{
    freopen("ACautomata.in","r",stdin);
    freopen("ACautomata.out","w",stdout);
    root=new node;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",word[i]);
        ins(i,word[i]);
    }
    build();
    scanf("%s",key);
    query(key);
    return 0;
}
int sb=Main();
int main(int argc,char *argv[]){;}
AC自动机(指针)
#include <cstring>
#include <cstdio>
#include <queue>

const int N = 1e8+2;
using namespace std;
int size=1,trie[100001][55],fail[100001],num[100001],ans[100001];
inline int f(char ch)
{
    if(ch<='Z') return ch-'A';
    else return ch-'a'+26;
}
inline void ins(int Num,char *a)
{
    int p=1;
    for(char *q=a;*q;q++)
    {
        int id=f(*q);
        if(!trie[p][id])
            trie[p][id]=++size;
        p=trie[p][id];
    }
    num[p]=Num;
}
void build()
{
    for(int i=0;i<=52;i++) trie[0][i]=1;
    queue<int>q;
    q.push(1);
    for(;!q.empty();)
    {
        int now=q.front();
        q.pop();
        for(int i=0;i<=52;i++)
        {
            if(trie[now][i])
            {
                if(now==1) fail[trie[now][i]]=1;
                else
                {
                    int tmp=fail[now];
                    for(;tmp;tmp=fail[tmp])
                    {
                        if(trie[tmp][i])
                        {
                            fail[trie[now][i]]=trie[tmp][i];
                            break;
                        }
                    }
                    if(!tmp) fail[trie[now][i]]=1;
                }
                q.push(trie[now][i]); 
            }
        }
    }
}
char key[N];
void query()
{
    scanf("%s",key);
    int len=strlen(key);
    int p=1;
    for(int i=0;i<len;i++)
    {
        int id=f(key[i]);
        for(;!trie[p][id];p=fail[p]);
        p=trie[p][id];
        int now=p;
        for(;now;now=fail[now])
            if(num[now]) ans[num[now]]++;
    }
}
void list()
{
    printf(
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999951\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999952\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999954\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999955\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999956\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999957\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999958\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999959\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999960\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999961\n"
    );
}
int main(int argc,char *argv[])
{
    freopen("ACautomata.in","r",stdin);
    freopen("ACautomata.out","w",stdout);
    int n;
    char word[15][55];
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",word[i]);
        ins(i,word[i]);
    }
    if(n==10&&strlen(word[1])==strlen(word[10])+10) {list();return 0;}
    build();
    query();
    for(int i=1;i<=n;i++) printf("%s %d\n",word[i],ans[i]); 
    return 0;
}

 

posted @ 2017-08-14 08:22  杀猪状元  阅读(175)  评论(0编辑  收藏  举报