HDU 2222 AC自动机
题目链接http://acm.hdu.edu.cn/showproblem.php?pid=2222.
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <cctype> #include <vector> #include <stack> #include <queue> #include <map> #include <algorithm> #include <iostream> #include <string> #include <set> #define X first #define Y second #define sqr(x) (x)*(x) #pragma comment(linker,"/STACK:102400000,102400000") using namespace std; const double PI = acos(-1.0); map<int, int>::iterator it; typedef long long LL ; template<typename T> void checkmin(T &x, T y) {x = min(x, y);} template<typename T> void checkmax(T &x, T y) {x = max(x, y);} //MAX_NODE = StringNumber * StringLength const int MAX_NODE = 500000 + 50; //节点个数,一般字符形式的题26个 const int CHILD_NUM = 26; //特定题目需要 const int mod = 20090717; class ACAutomaton { private: //每个节点的儿子,即当前节点的状态转移 int chd[MAX_NODE][CHILD_NUM]; //记录题目给的关键数据 int val[MAX_NODE]; //传说中的fail指针 int fail[MAX_NODE]; //队列,用于广度优先计算fail指针 int Q[MAX_NODE]; //字母对应的ID int ID[128]; //已使用节点个数 int sz; public: //初始化,计算字母对应的儿子ID,如:'a'->0 ... 'z'->25 void Initialize() { fail[0] = 0; for(int i = 0 ; i < CHILD_NUM ; i ++) { ID[i+'a'] = i; } } //重新建树需先Reset void Reset() { memset(chd[0] , -1 , sizeof(chd[0])); sz = 1; } //将权值为key的字符串a插入到trie中 void Insert(char *a, int key) { int p = 0; for(; *a ; ++ a) { int c = ID[*a]; if(chd[p][c] == -1) { memset(chd[sz] , -1 , sizeof(chd[sz])); val[sz] = 0; chd[p][c] = sz ++; } p = chd[p][c]; } val[p] += key; } //建立AC自动机,确定每个节点的权值以及状态转移 void Construct() { int *s = Q , *e = Q; for(int i = 0 ; i < CHILD_NUM ; i ++) { if(~chd[0][i]) { fail[ chd[0][i] ] = 0; *e ++ = chd[0][i]; } } while(s != e) { int r = *s++; for(int i = 0 ; i < CHILD_NUM ; i ++) { int u = chd[r][i]; if(~u) { *e ++ = u; int v = fail[r]; while(chd[v][i] == -1 && v)v = fail[v]; fail[u] = chd[v][i] == -1 ? 0 : chd[v][i]; } } } } //询问所给字符串包含多少个模式串 int Query(char *s) { int q = 0; int ret = 0; for(; *s; ++s) { int c = ID[*s]; while(chd[q][c] == -1 && q)q = fail[q]; q = chd[q][c]; if(q == -1)q = 0; int p = q; while(p) { if(val[p]) { ret += val[p]; val[p] = 0; } else { break; } p = fail[p]; } } return ret; } } AC; char s[1000005], t[10005]; int main() { int T; AC.Initialize(); scanf("%d", &T); while(T--) { AC.Reset(); int n; scanf("%d", &n); for(int i = 0; i < n; ++i) { scanf("%s", t); AC.Insert(t, 1); } AC.Construct(); scanf("%s", s); int res = AC.Query(s); printf("%d\n", res); } return 0; }