BZOJ 3172: [Tjoi2013]单词 AC自动机

3172: [Tjoi2013]单词


Description

某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。

Input

第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6

Output

输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。

Sample Input

3
a
aa
aaa

Sample Output

6
3
1

HINT

 

 

入门

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=1e6+10,mod=1e9+7,inf=2e9+10;

int nex[N][27],head,tail,pos[N],cnt = 1,fail[N],sum[N],q[N],n;
char a[N];
void insert(char *s,int &x) {
    int now = 1, len = strlen(s);
    for(int i = 0; i < len; ++i) {
        int index = s[i] - 'a';
        if(!nex[now][index]) nex[now][index] = ++cnt;
        now = nex[now][index];
        sum[now]++;
    }
    x = now;
}
void build_fail() {
    head = 0,tail = 0;
    q[tail++] = 1;
    fail[1] = 0;
    while(head != tail) {
        int now = q[head++];
        for(int i = 0; i < 26; ++i) {
            if(!nex[now][i]) continue;
            int p = fail[now];
            while(!nex[p][i]) p = fail[p];
            fail[nex[now][i]] = nex[p][i];
            q[tail++] = nex[now][i];
        }
    }
}
int main() {
    for(int i = 0; i < 26; ++i) nex[0][i] = 1;
    scanf("%d",&n);
    for(int i = 1; i <= n; ++i) {
        scanf("%s",a);
        insert(a,pos[i]);
    }//cout<<1<<endl;
    build_fail();
    for(int i = tail-1; i >=0; --i) sum[fail[q[i]]] += sum[q[i]];
    for(int i = 1; i <= n; ++i) cout<<sum[pos[i]]<<endl;
    return 0;
}

 

posted @ 2017-03-09 19:07  meekyan  阅读(177)  评论(0编辑  收藏  举报