这是一道简单版的AC自动机,之前我搞过一个这个东西,但是没具体学习,现在来学一下。
其实就是一个trie树上跑的kmp,每个节点存一个fail指针,指向前一次出现的地方。查询的时候直接加一起就行了。
题干:
题目背景 通过套取数据而直接“打表”过题者,是作弊行为,发现即棕名。 这是一道简单的AC自动机模板题。 用于检测正确性以及算法常数。 为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交。 管理员提示:本题数据内有重复的单词,且重复单词应该计算多次,请各位注意 题目描述 给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。 输入输出格式 输入格式: 第一行一个n,表示模式串个数; 下面n行每行一个模式串; 下面一行一个文本串。 输出格式: 一个数表示答案 输入输出样例 输入样例#1: 复制 2 a aa aa 输出样例#1: 复制 2 说明 subtask1[50pts]:∑length(模式串)<=10^6,length(文本串)<=10^6,n=1; subtask2[50pts]:∑length(模式串)<=10^6,length(文本串)<=10^6;
代码:
#include<iostream> #include<cstdio> #include<cmath> #include<ctime> #include<queue> #include<algorithm> #include<string> #include<cstring> using namespace std; #define duke(i,a,n) for(ll i = a;i <= n;i++) #define lv(i,a,n) for(int i = a;i >= n;i--) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } struct node { int fail; int vis[26]; int end; }ac[1100001]; int cnt = 0; inline void build(string s) { int l = s.length(); int now = 0; duke(i,0,l - 1) { if(ac[now].vis[s[i] - 'a'] == 0) ac[now].vis[s[i] - 'a'] = ++cnt;//鏂板缓鑺傜偣 now = ac[now].vis[s[i] - 'a']; } ac[now].end ++; } int n; void get_fail() { queue <int> q; duke(i,0,25) { if(ac[0].vis[i] != 0) { ac[ac[0].vis[i]].fail = 0; q.push(ac[0].vis[i]); } } while(!q.empty()) //bfs { int u = q.front(); q.pop(); duke(i,0,25) { if(ac[u].vis[i] != 0) { ac[ac[u].vis[i]].fail = ac[ac[u].fail].vis[i]; q.push(ac[u].vis[i]); } else ac[u].vis[i] = ac[ac[u].fail].vis[i]; } } } int query(string s) { int l = s.length(); int now = 0,ans = 0; // cout<<l<<endl; duke(i,0,l - 1) { now = ac[now].vis[s[i] - 'a']; for(int t = now;ac[t].end != -1;t = ac[t].fail) { ans += ac[t].end; ac[t].end = -1; } } return ans; } int main() { cin>>n; string s; // cout<<n<<endl; for(int i = 1;i <= n;i++) { cin>>s; build(s); // printf("%d ",s.length()); } ac[0].fail = 0; get_fail(); cin>>s; printf("%d",query(s)); return 0; } /* 2 a aa aa */