PDF (English) | Statistics | Forum |
Time Limit: 5 second(s) | Memory Limit: 128 MB |
A string is a finite sequence of symbols that are chosen from an alphabet. In this problem you are given a string T and n queries each with a string Pi, where the strings contain lower case English alphabets only. You have to find the number of times Pi occurs as a substring of T.
Input starts with an integer T (≤ 10), denoting the number of test cases.
Each case starts with a line containing an integer n (1 ≤ n ≤ 500). The next line contains the string T (1 ≤ |T| ≤ 106). Each of the next n lines contains a string Pi(1 ≤ |Pi| ≤ 500).
For each case, print the case number in a single line first. Then for each string Pi, report the number of times it occurs as a substring of T in a single line.
Sample Input |
Output for Sample Input |
2 5 ababacbabc aba ba ac a abc 3 lightoj oj light lit |
Case 1: 2 3 1 4 1 Case 2: 1 1 0 |
1. Dataset is huge, use faster I/O methods.
2. If S is a string then |S| denotes the length of S.
题目链接:http://lightoj.com/volume_showproblem.php?problem=1427
题目大意:问单词在给定的段落中出现的次数
题目分析:AC自动机,注意单词可能重复,插单词的时候标记一下,把idx转到其第一次出现的坐标,本题动态new的话,不delete会mle,delete会超时
下面给出三种常见姿势和一个神奇姿势:
1.普通静态指针型 (3956 ms)
#include <cstdio> #include <cstring> int const MAXN = 1e6 + 5; int const MAXM = 505; char s[MAXM], t[MAXN]; int tail, head, sz; int ans[MAXM], cg[MAXM]; struct NODE { int cnt; int id; int idx; NODE *fail; NODE *next[26]; }*q[MAXM * MAXM], *root, *f, node[MAXM * MAXM]; inline void Newnode(NODE * &x) { x = &node[sz]; x -> id = sz ++; x -> cnt = 0; x -> idx = 0; x -> fail = NULL; memset(x -> next, NULL, sizeof(x -> next)); } inline void Init() { sz = 0; head = tail = 0; f = &node[0]; f -> id = 0; f -> cnt = 0; f -> idx = 0; f -> fail = NULL; memset(f -> next, NULL, sizeof(f -> next)); Newnode(root); } inline void Insert(NODE *p, char *s, int id) { int len = strlen(s); for(int i = 0; i < len; i++) { int idx = s[i] - 'a'; if(p -> next[idx] == NULL) Newnode(p -> next[idx]); p = p -> next[idx]; } if(p -> cnt) cg[id] = p -> id; else { p -> id = id; p -> cnt = 1; } } inline void Build_AC(NODE *root) { q[tail ++] = root; while(tail != head) { NODE *p = q[head ++]; for(int i = 0; i < 26; i++) { if(p -> next[i] != NULL) { if(p == root) p -> next[i] -> fail = root; else { NODE *tmp = p -> fail; while(tmp != NULL) { if(tmp -> next[i] != NULL) { p -> next[i] -> fail = tmp -> next[i]; break; } tmp = tmp -> fail; } if(tmp == NULL) p -> next[i] -> fail = root; } q[tail ++] = p -> next[i]; } } } } inline void Query(NODE *root, char *t) { NODE *p = root; int len = strlen(t); for(int i = 0; i < len; i++) { int idx = t[i] - 'a'; while(p != root && p -> next[idx] == NULL) p = p -> fail; if(p -> next[idx] == NULL) p = root; else p = p -> next[idx]; NODE *tmp = p; while(tmp != root) { ans[tmp -> id] += tmp -> cnt; tmp = tmp -> fail; } } } int main() { int T; scanf("%d", &T); for(int ca = 1; ca <= T; ca++) { memset(ans, 0, sizeof(ans)); memset(cg, -1, sizeof(cg)); Init(); int n; scanf("%d", &n); scanf("%s", t); for(int i = 0; i < n; i++) { scanf("%s", s); Insert(root, s, i); } Build_AC(root); Query(root, t); printf("Case %d:\n", ca); for(int i = 0; i < n; i++) { if(cg[i] != -1) printf("%d\n", ans[cg[i]]); else printf("%d\n", ans[i]); } } }
2.Tire图优化静态指针型 (4000ms) 。。反而更慢
#include <cstdio> #include <cstring> int const MAXN = 1e6 + 5; int const MAXM = 505; char s[MAXM], t[MAXN]; int tail, head, sz; int ans[MAXM], cg[MAXM]; struct NODE { int cnt; int id; int idx; NODE *fail; NODE *next[26]; }*q[MAXM * MAXM], *root, *f, node[MAXM * MAXM]; inline void Newnode(NODE * &x) { x = &node[sz]; x -> id = sz ++; x -> cnt = 0; x -> idx = 0; x -> fail = NULL; memset(x -> next, NULL, sizeof(x -> next)); } inline void Init() { sz = 0; head = tail = 0; f = &node[0]; f -> id = 0; f -> cnt = 0; f -> idx = 0; f -> fail = NULL; memset(f -> next, NULL, sizeof(f -> next)); Newnode(root); } inline void Insert(NODE *p, char *s, int id) { int len = strlen(s); for(int i = 0; i < len; i++) { int idx = s[i] - 'a'; if(p -> next[idx] == NULL) Newnode(p -> next[idx]); p = p -> next[idx]; } if(p -> cnt) cg[id] = p -> id; else { p -> id = id; p -> cnt = 1; } } inline void Build_AC(NODE *root) { q[tail ++] = root; while(tail != head) { NODE *p = q[head ++]; for(int i = 0; i < 26; i++) { if(p -> next[i] != NULL) { if(p == root) p -> next[i] -> fail = root; else p -> next[i] -> fail = p -> fail -> next[i]; q[tail ++] = p -> next[i]; } else { if(p == root) p -> next[i] = root; else p -> next[i] = p -> fail -> next[i]; } } } } inline void Query(NODE *root, char *t) { NODE *p = root; int len = strlen(t); for(int i = 0; i < len; i++) { int idx = t[i] - 'a'; while(p != root && p -> next[idx] == NULL) p = p -> fail; if(p -> next[idx] == NULL) p = root; else p = p -> next[idx]; NODE *tmp = p; while(tmp != root) { ans[tmp -> id] += tmp -> cnt; tmp = tmp -> fail; } } } int main() { int T; scanf("%d", &T); for(int ca = 1; ca <= T; ca++) { memset(ans, 0, sizeof(ans)); memset(cg, -1, sizeof(cg)); Init(); int n; scanf("%d", &n); scanf("%s", t); for(int i = 0; i < n; i++) { scanf("%s", s); Insert(root, s, i); } Build_AC(root); Query(root, t); printf("Case %d:\n", ca); for(int i = 0; i < n; i++) { if(cg[i] != -1) printf("%d\n", ans[cg[i]]); else printf("%d\n", ans[i]); } } }
3.静态数组Trie图优化 (2668 ms)
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; int const MAXN = 1e6 + 5; int const MAXM = 505 * 505 ; char t[MAXN], s[MAXM]; int n, ans[MAXM], cg[MAXM]; struct AC { int next[MAXM][26], fail[MAXM], end[MAXM], id[MAXM]; int root, tot; inline int Newnode() { for(int i = 0; i < 26; i++) next[tot][i] = -1; end[tot] = 0; fail[tot] = 0; return tot ++; } inline void Init() { tot = 0; root = Newnode(); } inline void Insert(char *s, int idx) { int len = strlen(s); int now = root; for(int i = 0; i < len; i++) { int idx = s[i] - 'a'; if(next[now][idx] == -1) next[now][idx] = Newnode(); now = next[now][idx]; } if(end[now]) cg[idx] = id[now]; else { end[now] = 1; id[now] = idx; } } inline void Build() { queue <int> q; q.push(root); while(!q.empty()) { int now = q.front(); q.pop(); for(int i = 0; i < 26; i++) { if(next[now][i] == -1) { if(now == root) next[now][i] = root; else next[now][i] = next[fail[now]][i]; } else { if(now == root) fail[next[now][i]] = root; else fail[next[now][i]] = next[fail[now]][i]; q.push(next[now][i]); } } } } inline void Query(char *s) { int now = root; int len = strlen(s); for(int i = 0; i < len; i++) { int idx = s[i] - 'a'; while(now != root && next[now][idx] == -1) now = fail[now]; now = next[now][idx]; int tmp = now; while(tmp != root) { ans[id[tmp]] += end[tmp]; tmp = fail[tmp]; } } } }ac; int main() { int T; scanf("%d", &T); for(int ca = 1; ca <= T; ca++) { memset(cg, -1, sizeof(cg)); memset(ans, 0, sizeof(ans)); ac.Init(); scanf("%d", &n); scanf("%s", t); for(int i = 0; i < n; i++) { scanf("%s", s); ac.Insert(s, i); } ac.Build(); ac.Query(t); printf("Case %d:\n", ca); for(int i = 0; i < n; i++) { if(cg[i] != -1) printf("%d\n", ans[cg[i]]); else printf("%d\n", ans[i]); } } }
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; int const MAXN = 1e6 + 5; int const MAXM = 505 * 505; char t[MAXN], s[MAXM]; int ans[MAXM], pos[MAXM]; int n; struct AC { int next[MAXM][26], fail[MAXM]; int st[MAXM]; int root, tot, top; inline int Newnode() { memset(next[tot], -1, sizeof(next[tot])); ans[tot] = 0; fail[tot] = 0; return tot ++; } inline void Init() { top = 0; tot = 0; root = Newnode(); } inline void Insert(char *s, int id) { int len = strlen(s); int now = root; for(int i = 0; i < len; i++) { int idx = s[i] - 'a'; if(next[now][idx] == -1) next[now][idx] = Newnode(); now = next[now][idx]; } pos[id] = now; } inline void Build() { queue <int> q; q.push(root); while(!q.empty()) { int now = q.front(); q.pop(); for(int i = 0; i < 26; i++) { if(next[now][i] == -1) { if(now == root) next[now][i] = root; else next[now][i] = next[fail[now]][i]; } else { if(now == root) fail[next[now][i]] = root; else fail[next[now][i]] = next[fail[now]][i]; q.push(next[now][i]); st[++ top] = next[now][i]; } } } } inline void Query(char *s) { int now = root; int len = strlen(s); for(int i = 0; i < len; i++) { int idx = s[i] - 'a'; now = next[now][idx]; ans[now] ++; } while(top) { int p = st[top]; ans[fail[p]] += ans[p]; top --; } } }ac; int main() { int T; scanf("%d", &T); for(int ca = 1; ca <= T; ca++) { ac.Init(); scanf("%d", &n); scanf("%s", t); for(int i = 1; i <= n; i++) { scanf("%s", s); ac.Insert(s, i); } ac.Build(); ac.Query(t); printf("Case %d:\n", ca); for(int i = 1; i <= n; i++) printf("%d\n", ans[pos[i]]); } }