题目大意:
给定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 }
我还在坚持,我还未达到我所想,梦~~一直在