【HNOI2004】L语言
Description
给定n个模式串和m个文本串,对于每个文本串,求出这个文本串在模式串中最大匹配长度。
Solution
我们采用AC自动机求解。
首先构建自动机,在Trie上保存模式串,之后通过bfs求出失配数组(AC自动机的模板操作),之后处理匹配操作。
这里的一个难点就是我们需要记录最大的匹配长度(而不是是否能匹配),因此我们开一个数组记录当前文本串能匹配的最大长度是多少,那么当AC自动机匹配完一个模式串时,如果文本串中这个模式串之前都匹配完成,那么我们在这里标记。跑一边AC自动机,最后倒序扫一遍标记数组,第一个扫描到标记的位置就是最大长度。
Code
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int n, m; 5 char c[21][11], s[1050010]; 6 int ch[100010][27], val[100010], vis[1050010], dep[100010], f[100010], tot; 7 void insert(char *a) { 8 int now = 0; 9 int l = strlen(a); 10 for (int i = 0; i < l; ++i) { 11 if (!ch[now][a[i] - 'a']) { 12 ch[now][a[i] - 'a'] = ++tot; 13 dep[tot] = dep[now] + 1; 14 } 15 now = ch[now][a[i] - 'a']; 16 } 17 val[now] = 1; 18 return ; 19 } 20 queue <int> q; 21 void bfs() { 22 for (int i = 0; i < 26; ++i) { 23 if (ch[0][i]) { 24 f[ch[0][i]] = 0; 25 q.push(ch[0][i]); 26 } 27 } 28 while (!q.empty()) { 29 int now = q.front(); 30 q.pop(); 31 for (int i = 0; i < 26; ++i) { 32 if (ch[now][i]) f[ch[now][i]] = ch[f[now]][i], q.push(ch[now][i]); 33 else ch[now][i] = ch[f[now]][i]; 34 } 35 } 36 return ; 37 } 38 int query(char *a) { 39 vis[0] = 1; 40 int now = 0, l = strlen(a); 41 for (int i = 0; i < l; ++i) { 42 now = ch[now][a[i] - 'a']; 43 for (int j = now; j; j = f[j]) 44 if (val[j] && vis[i + 1 - dep[j]]) { 45 vis[i + 1] = 1; 46 break ; 47 } 48 } 49 for (int i = l; i; --i) 50 if (vis[i]) return i; 51 return 0; 52 } 53 int main() { 54 scanf("%d%d", &n, &m); 55 for (register int i = 1; i <= n; ++i) { 56 scanf("%s", c[i]); 57 insert(c[i]); 58 } 59 bfs(); 60 for (register int i = 1; i <= m; ++i) { 61 memset(vis, 0, sizeof(vis)); 62 scanf("%s", s); 63 printf("%d\n", query(s)); 64 } 65 return 0; 66 }