• bzoj 3172 单词 ac自动机|后缀数组


    题目大意:

    给定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
    " , ac.val[pos[i]]);
    83     return 0;
    84 }
  • 相关阅读:
    在C语言中,double、long、unsigned、int、char类型数据所占字节数
    C++基础之头文件和源文件的关系
    Activity与Fragment数据传递之Activity从Fragment获取数据 分类: Android 2015-07-02 09:56 12人阅读 评论(0) 收藏
    Activity与Fragment数据传递之Fragment从Activity获取数据 分类: Android 2015-07-01 14:12 17人阅读 评论(0) 收藏
    Java反射机制和对象序列化 分类: Java 2015-06-26 12:08 21人阅读 评论(0) 收藏
    Android通过播放多张图片形成一个动画 分类: Android 2015-04-24 14:05 16人阅读 评论(0) 收藏
    jvm参数的配置、垃圾回收器的配置
    selenium2工作原理
    LeetCode#1 Two Sum
    LeetCode#27 Remove Element
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/5155367.html
Copyright © 2020-2023  润新知