• Keywords Search HDU2222 AC自动机模板题


    ac自动机说起来很复杂,其实和kmp是一样的思路,都是寻找相同前后缀,减少跳的次数。只要理解了kmp是怎么求next数组的,ac自动机bfs甚至比knp还好写。

    这里大致说一下kmp求next数组的方法吧,假设现在要求第c个字符的next值(假设这个c很大,这样画图出来比较清晰方便理解),因为遍历过程中我们已经知道了第c-1个字符的next为x(假设比c小很多),即next[c-1] = x。那就代表我们知道了a[1]—a[x]这一段和a[c-1-x]—a[c-1]这一段是相等的对吧。

    那么现在有两种情况

    一。a[x+1] 和 a[c]相等,那么显然变成了a[1]—a[x+1] 这一段和a[c-1-x]—a[c]这一段相等,即c位置的相同前后缀长度比c-1多了1,就是next[c-1]+1;

    即原来是:

    1——————————x      == c-1-x ————————————————c-1  ① 由于a[x+1] == a[c],变成了

    1——————————x+1  == c-1-x——————————————————c

    二。如果不相等,那么我们在1——x这一段下功夫,假设next[x] = y,即1——y == x-y——x这两段相等,注意根据①式,x-y——x == c-1-y——c-1,画个图就很清楚了,所以如果a[y+1] == a[c],那么相同前后缀长度就是y+1了。

    即因为

    1——————————x   ==    c-1-x————————————————c-1  

    1——y    ==   x-y———x   ==    c-1-x——c-1-x+y     ==       c-1-y————c-1   由于a[y+1] == a[c],变成了

    1——y+1             ==          c-1-y——————c 

    那如果a[y+1] 与a[c]还是不相等怎么办?其实细心的话应该发现这是一个递归过程了——只要再找next[y],循环上面的过程就可以了,想明白这个过程再去看求next数组的代码就很容易理解了。

    最后还是上这道题代码:

      1 #include <iostream>
      2 #include <string.h>
      3 #include <cstdio>
      4 #include <queue>
      5 #include <set>
      6 #include <stack>
      7 #include <math.h>
      8 #include <string>
      9 #include <algorithm>
     10 
     11 #define SIGMA_SIZE 26
     12 #define pii pair<int,int>
     13 #define lson rt<<1
     14 #define rson rt<<1|1
     15 #define lowbit(x) (x&-x)
     16 #define fode(i, a, b) for(int i=a; i>=b; i--)
     17 #define foe(i, a, b) for(int i=a; i<=b; i++)
     18 #define fod(i, a, b) for(int i=a; i>b; i--)
     19 #define fo(i, a, b) for(int i=a; i<b; i++)
     20 //#pragma warning ( disable : 4996 )
     21 
     22 using namespace std;
     23 typedef long long LL;
     24 inline LL LMax(LL a, LL b) { return a>b ? a : b; }
     25 inline LL LMin(LL a, LL b) { return a>b ? b : a; }
     26 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
     27 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
     28 inline int Max(int a, int b) { return a>b ? a : b; }
     29 inline int Min(int a, int b) { return a>b ? b : a; }
     30 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
     31 inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
     32 const LL INF = 0x3f3f3f3f3f3f3f3f;
     33 const LL lmod = 1e9+7;
     34 const int mod = 10000;
     35 const double eps = 1e-8;
     36 const int inf = 0x3f3f3f3f;
     37 const int maxk = 1e5+5;
     38 const int maxm = 510*510;
     39 const int maxn = 5e5+10;
     40 
     41 struct node {
     42     node *fail, *s[26];
     43     int w;
     44     node() {}
     45     
     46     void init() {
     47         fail = NULL;
     48         fo(i, 0, 26) s[i] = NULL;
     49         w = 0;
     50     }
     51 }*head;
     52 
     53 
     54 int n, ans;
     55 char str[1000010];
     56 queue<node*> q;
     57 
     58 node* getfail(node* p, int x)
     59 {
     60     if (p->s[x] != NULL) return p->s[x];
     61     else {
     62         if (p == head) return head;
     63         else return getfail(p->fail, x);
     64     }
     65 }
     66 
     67 void build()
     68 {
     69     node* root = head;
     70     node* tmp;
     71 
     72     int len = strlen(str);
     73     for ( int j = 0; j < len; j++ ) 
     74     {
     75         int k = str[j]-'a';
     76         if (root->s[k] == NULL) {
     77             tmp = new node; tmp->init();
     78             tmp->fail = head;
     79             root->s[k] = tmp; 
     80         }
     81 
     82         root = root->s[k];
     83         //标记单词结尾
     84         if (j == len-1) root->w++;
     85     }
     86 }
     87 
     88 void build_ac()
     89 {
     90     node* r;
     91     while(!q.empty()) q.pop();
     92     q.push(head);
     93     while(!q.empty())
     94     {
     95         r = q.front(); q.pop();
     96         fo(j, 0, 26)
     97         {
     98             if (r->s[j] != NULL) {
     99                 q.push(r->s[j]);
    100                 if (r == head) r->s[j]->fail = head;
    101                 else r->s[j]->fail = getfail(r->fail, j);
    102             }
    103         }
    104     }
    105     return;
    106 }
    107 
    108 void solve()
    109 {
    110     int len = strlen(str);
    111     node *tmp, *r = head;
    112     fo(j, 0, len)
    113     {
    114         int k = str[j]-'a';
    115         //找到前缀
    116         while( r->s[k]==NULL && r != head ) r = r->fail; 
    117         //自动机向下匹配
    118         //如果可以匹配,则进入下一节点,否则返回头节点
    119         r = (r->s[k]==NULL) ? head : r->s[k];
    120         tmp = r;
    121 
    122         //如果单词a出现,则他的前缀也全部出现过
    123         while(tmp != head) {
    124             ans += tmp->w;
    125             tmp->w = 0;
    126             tmp = tmp->fail;
    127         }   
    128     }
    129     return;
    130 }
    131 
    132 
    133 
    134 void init()
    135 {
    136     cin >> n; ans = 0;
    137     head = new node, head->init();
    138     foe(i, 1, n)
    139         scanf("%s", str), build();
    140 
    141     build_ac();
    142     scanf("%s", str);
    143 }
    144 
    145 int main()
    146 {
    147 
    148     #ifndef ONLINE_JUDGE
    149         freopen("input.txt", "r", stdin);
    150     #endif
    151     
    152     int t; cin >> t;
    153     while(t--)
    154     {
    155         init();
    156         solve();
    157         printf("%d
    ", ans);
    158     }
    159 
    160     return 0;
    161 }
    View Code
  • 相关阅读:
    Regular进阶: 几点性能优化的建议
    总结常见的违背Rest原则的接口设计做法
    如何进行用户访谈更容易获得全面而有效的信息
    关于以太坊智能合约在项目实战过程中的设计及经验总结(2)
    关于以太坊智能合约在项目实战过程中的设计及经验总结(1)
    字节码执行方式--解释执行和JIT
    Redis数据库结构与读写原理
    移动端工程架构与后端工程架构的思想摩擦之旅(2)
    类文件结构与javap的使用
    JVM垃圾收集器(1)
  • 原文地址:https://www.cnblogs.com/chaoswr/p/9783281.html
Copyright © 2020-2023  润新知