题目大意:

给定n个字符串连成了一篇文章,问每个字符串在这篇文章中出现的次数,可重复覆盖

这里ac自动机和后缀数组都可以做

当然后缀数组很容易就解决,但是相对时间消耗高

这里就只讲ac自动机了

将每个字符串放入ac自动机中,这里需要记录到达每个ac自动机上的节点出现这个状态有多少次

而我们添加字符串进入的时候,应该是把经过的每个节点的val都++,说明这个字符串多出现了一次这个值

然后因为自己用字符串在ac自动机上走肯定是到达离root最近的点,也就是说有很多的点会不断通过fail指针指向他,而这些点都是包含了这个字符串的

那也就是说我们需要考虑 val[fail[i]] += val[i]

这里一定是需要从最底层的点不断fail上来,我们需要找到一个合适的更新val点的顺序

可以考虑在我们构建后缀自动机的时候我们采用的是利用队列bfs的过程,那也就是说进入的点是符合最大长度从小到大的性质的

而fail指向的总是比它长度更小的点,所以根据进入队列的点的逆顺序来更新val即可

也就是每次点进队列都 que[cnt++] = u;

最后

for(int i=sz-1 ; i>0 ; i--)
  val[fail[que[i]]]+=val[que[i]];

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <queue>
 4 #include <vector>
 5 #include <iostream>
 6 #include <algorithm>
 7 #include <map>
 8 using namespace std;
 9 #define clr(x) memset(x , 0 , sizeof(x))
10 #define set(x) memset(x , -1 , sizeof(x))
11 typedef long long LL ;
12 
13 const int CHAR_SIZE = 26;
14 const int MAX_SIZE = 1000005;
15 const int M = 10000 ;
16 
17 struct AC_Machine{
18     int ch[MAX_SIZE][CHAR_SIZE] , val[MAX_SIZE] , fail[MAX_SIZE] , que[MAX_SIZE];
19     int sz;
20     bool vis[MAX_SIZE];
21     void init(){
22         sz = 1;
23         clr(ch[0]) , clr(val) , clr(vis);
24     }
25 
26     int insert(string s){
27         int n = s.length();
28         int u=0 ;
29         for(int i=0 ; i<n ; i++){
30             int c = s[i]-'a';
31             if(!ch[u][c]){
32                 clr(ch[sz]) , val[sz]=0;
33                 ch[u][c] = sz++;
34             }
35             u = ch[u][c];
36             val[u]++;
37         }
38         return u;
39     }
40 
41     void get_fail(){
42         queue<int> Q;
43         fail[0] = 0;
44         int cnt = 0;
45         for(int c=0 ; c<CHAR_SIZE ; c++){
46             int u = ch[0][c];
47             if(u){Q.push(u);fail[u]=0,que[cnt++]=u;}
48         }
49         while(!Q.empty()){
50             int r = Q.front();
51             Q.pop();
52             for(int c=0 ; c<CHAR_SIZE ; c++){
53                 int u = ch[r][c];
54                 if(!u){ch[r][c] = ch[fail[r]][c]; continue;}
55                 fail[u] = ch[fail[r]][c];
56                 Q.push(u);
57                 que[cnt++]=u;
58             }
59         }
60     }
61     void updateVal(){
62         for(int i=sz-1 ; i>0 ; i--)
63             val[fail[que[i]]]+=val[que[i]];
64     }
65 }ac;
66 int n , pos[205];
67 string s[205];
68 
69 int main()
70 {
71    // freopen("a.in" , "r" , stdin);
72    // freopen("out.txt" , "w" , stdout);
73     scanf("%d" , &n);
74     ac.init();
75     for(int i=0 ; i<n ; i++){
76         cin>>s[i];
77         pos[i] = ac.insert(s[i]);
78     }
79     ac.get_fail();
80     ac.updateVal();
81     for(int i=0 ; i<n ; i++)
82         printf("%d\n" , ac.val[pos[i]]);
83     return 0;
84 }

 

 posted on 2016-01-24 16:46  Love风吟  阅读(355)  评论(0编辑  收藏  举报