【AC自动机】单词

【题目链接】

https://loj.ac/problem/10060

 

【题意】

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

 

【题解】

与AC自动机模板题3类似,但是这个题目记录的子串是不能重叠的。

 

利用下标从后往前历遍,然后把对应的位置的地方叠加到公共后缀。原因是:如果该单词出现过,那么对应的公共后缀肯定也出现过。

 

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int N = 1005;
 5 const int M = 1e6+10;
 6 char S[N][205];
 7 int Trie[M][26],fail[M],End[M],Sz[M];
 8 int Q[M],Head,Tail;
 9 int head[M],nxt[M],to[M],cnt;
10 int n,idx=1;
11 
12 void Add_edge(int u,int v);
13 void dfs(int u);
14 void Insert( char s[] , int Id){
15     int p = 1 ;
16     for(int i=0;s[i];i++){
17         int t = s[i] - 'a' ;
18         if( !Trie[p][t] )
19             Trie[p][t] = ++idx ;
20         p = Trie[p][t] ;
21         Sz[p] ++ ;
22     }
23     End[Id] = p ;
24 }
25 void Build(){
26     Head = 1 , Tail = 0;
27     for(int i=0;i<26;i++) Trie[0][i] = 1 ;
28 
29     Q[++Tail] = 1 ;
30     while( Head <= Tail ){
31         int u = Q[Head++];
32         for(int i=0;i<26;i++){
33             int To = Trie[u][i];
34             if( To ){
35                 fail[To] = Trie[fail[u]][i];
36                 Q[++Tail] = To;
37             }else{
38                 Trie[u][i] = Trie[fail[u]][i];
39             }
40         }
41     }
42 }
43 void Query(){
44 
45     /*for(int i=1,p=1;i<=n;i++){
46         p = 1 ;
47         for(int j=0;S[i][j];j++){
48             int t = S[i][j] - 'a' ;
49             p = Trie[p][t];
50             Sz[p] ++;
51         }
52     }*/
53 
54     for(int i=idx;i>=1;i--){
55 //        Add_edge(fail[i],i);
56         Sz[fail[Q[i]]] += Sz[Q[i]];
57     }
58     //dfs(1);
59     for(int i=1;i<=n;i++){
60         printf("%d\n",Sz[End[i]]);
61     }
62 }
63 int main()
64 {
65     scanf("%d",&n);
66     for(int i=1;i<=n;i++){
67         scanf("%s",S[i]);
68         Insert(S[i],i);
69 
70         //printf("### %s ### \n",S[i]);
71     }
72     Build();
73     //printf("@@@@\n");
74     Query();
75     return 0;
76 }
77 void dfs(int u){
78     for(int i=head[u];i;i=nxt[i] ){
79         int To = to[i] ;
80         dfs( To ) ;
81         Sz[u] += Sz[To] ;
82     }
83 }
84 void Add_edge(int u,int v){
85     nxt[++cnt] = head[u];
86     head[u] = cnt ;
87     to[cnt] = v ;
88 }
不重叠统计次数

 

posted @ 2019-08-17 00:27  Osea  阅读(240)  评论(0编辑  收藏  举报