zoukankan      html  css  js  c++  java
  • bzoj 2754 ac自动机

    第一道AC自动机题目。

    记一下对AC自动机的理解吧:

    AC自动机=Trie+KMP。即在Trie上应用KMP思想,实现多Pattern的匹配问题。

    复杂度是预处理O(segma len(P)),匹配是O(len(T))。应该也是下界了。

    它预处理做了以下事情:

      1、建立所有Pattern的Trie

      2、计算出fail和last数组

    匹配时和KMP很像。

    我对fail和last的理解:

      对于一棵Trie,上面的一个节点对应一个字符串,该字符串是root到该节点的路径上,边代表的字符连接起来的。

    fail[i]是一个指针,它指向一个节点f,使得f代表的字符串是i代表的字符串最长的一个后缀(所以f的深度一定比i小)。

    last[i]也是一个指针,它指向一个节点f,使得f代表的字符串是i代表的字符串的一个后缀且该后缀也是一个Pattern。(如果不存在则指向根)。

    我们将根节点代表的字符串理解成空串,空串是任何字符串的子串。

    对于匹配过程,我们将Text串也想成一个由点和边组成的链,我们从最左边的点开始向右开始匹配。

    我们以Text串的位置为阶段进行匹配,如果Trie的当前节点存在一条边,使得它代表的字符串和text串一致,就两边都前进。如果不存在,trie中的节点就不断通过fail向上跳,直到存在边或到达根,如果存在边就同时向下走,否则(即到达根且根也没有对应边),那就trie保持在根,text串到下一节点。

    然后每到一个新的trie节点就查看是否匹配到(要用到last数组).


    去重的几种方式:

      1、set

      2、sort+unique

      3、mark+vector

    各有特点,

    set是实时添加和查询,O(nlogn)。

    sort+unique是添加完后查询(多用于离散话),也是O(nlogn)(常数比前者小)。

    mark+vector,要求范围较小(10^7以内),O(n)

      1 /**************************************************************
      2     Problem: 2754
      3     User: idy002
      4     Language: C++
      5     Result: Accepted
      6     Time:1320 ms
      7     Memory:13264 kb
      8 ****************************************************************/
      9  
     10 #include <cstdio>
     11 #include <cctype>
     12 #include <queue>
     13 #include <vector>
     14 #include <set>
     15 #include <map>
     16 #include <algorithm>
     17 #define maxn 100010
     18 using namespace std;
     19  
     20 typedef vector<int> String;
     21  
     22 int gint() {
     23     int rt;
     24     char ch, opt;
     25     while( !isdigit(ch=getchar()) ) opt=ch;
     26     rt=ch-'0';
     27     while( isdigit(ch=getchar()) ) rt=rt*10+ch-'0';
     28     return rt;
     29 }
     30  
     31 int n, m;
     32 int ans[2][maxn];
     33 String str[maxn], ss;
     34 bool mark[maxn];
     35 vector<int> in;
     36  
     37 struct AC {
     38     map<int,int> son[maxn];
     39     set<int> st;
     40     vector<int> stk[maxn];
     41     int fail[maxn], last[maxn], ntot;
     42  
     43     void insert( int id, String &p ) {
     44         int u=0;
     45         for( int i=0; i<p.size(); i++ ) {
     46             int c=p[i];
     47             if( !son[u][c] ) son[u][c] = ++ntot;
     48             u=son[u][c];
     49         }
     50         stk[u].push_back(id);
     51     }
     52     void build() {
     53         queue<int> qu;
     54         for( map<int,int>::iterator it=son[0].begin(); it!=son[0].end(); ++it ) {
     55             int v=it->second;
     56             qu.push(v);
     57             fail[v] = last[v] = 0;
     58         }
     59         while(!qu.empty()) {
     60             int u=qu.front();
     61             qu.pop();
     62             for( map<int,int>::iterator it=son[u].begin(); it!=son[u].end(); ++it ) {
     63                 int c=it->first;
     64                 int v=it->second;
     65                 int w=fail[u];
     66                 while( w && !son[w][c] ) w=fail[w];
     67                 int x=son[w][c];
     68                 fail[v] = x;
     69                 last[v] = stk[x].size() ? x : last[x];
     70                 qu.push(v);
     71             }
     72         }
     73     }
     74     void add( int u ) {
     75         if( !u ) return;
     76         add(last[u]);
     77         for( int t=0; t<stk[u].size(); t++ ) {
     78             if( mark[stk[u][t]] ) continue;
     79             mark[stk[u][t]] = true;
     80             in.push_back( stk[u][t] );
     81         }
     82     }
     83     void search( int id, String &T ) {
     84         st.clear();
     85         int u=0;
     86         for( int i=0; i<T.size(); i++ ) {
     87             while( u && !son[u][T[i]] ) u=fail[u];
     88             u=son[u][T[i]];
     89             if( stk[u].size() ) add(u);
     90             else add(last[u]);
     91         }
     92         ans[0][id] += in.size();
     93         for( int t=0; t<in.size(); t++ ) {
     94             ans[1][in[t]]++;
     95             mark[in[t]]=false;
     96         }
     97         in.clear();
     98     }
     99 }ac;
    100  
    101  
    102 int main() {
    103     n = gint();
    104     m = gint();
    105     for( int i=1,z; i<=n; i++ ) {
    106         z = gint();
    107         while(z--) str[i].push_back( gint() );
    108         str[i].push_back(-1);
    109         z = gint();
    110         while(z--) str[i].push_back( gint() );
    111     }
    112     for( int i=1,z; i<=m; i++ ) {
    113         ss.clear();
    114         z = gint();
    115         while(z--) ss.push_back( gint() );
    116         ac.insert( i, ss );
    117     }
    118     ac.build();
    119     for( int i=1; i<=n; i++ )
    120         ac.search( i, str[i] );
    121     for( int i=1; i<=m; i++ )
    122         printf( "%d
    ", ans[1][i] );
    123     for( int i=1; i<=n; i++ )
    124         printf( "%d%s", ans[0][i], i==n ? "" : " " );
    125 }
    View Code
  • 相关阅读:
    AtCoder Grand Contest 032-B
    AtCoder Grand Contest 032 A
    高橋君とカード / Tak and Cards AtCoder
    Divisibility by 25 CodeForces
    Fire Again CodeForces
    cctype函数 (字符类型判断)
    蓝桥杯--- 历届试题 国王的烦恼 (并查集)
    蓝桥杯---买不到的数目
    算法课(经典贪心)
    完美的数字
  • 原文地址:https://www.cnblogs.com/idy002/p/4333114.html
Copyright © 2011-2022 走看看