1. 程式人生 > >COGS 1913. AC自動機

COGS 1913. AC自動機

stdin 題目 rapi fault opened n) pla http lis

★★ 輸入文件: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;
}

COGS 1913. AC自動機