题意:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6138
给出n个字符串,m个询问,询问x和y两个字符的最长公共子串的长度,而且要求这个子串为这n个字符串中任意一个(或多个)的前缀。
思路:
AC自动机。
每个节点end数组都保存当前节点到根节点的距离。将n个字符串保加入AC自动机。然后对x在自动机上跑一边标记节点,然后再对y跑一遍,遇到标记的节点就更新答案。注意每次还要再去除标记。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const LL MOD = 1e9 + 7;
const int MAXN = 1e5 + 10;
struct ACauto {
int next[MAXN][26], fail[MAXN], end[MAXN], vis[MAXN];
int root, sz;
int newnode() {
for (int i = 0; i < 26; i++)
next[sz][i] = -1;
end[sz++] = 0;
return sz - 1;
}
void init() {
sz = 0;
root = newnode();
}
int idx(char c) {
return c - 'a';
}
void insert(char *buf) {
int len = strlen(buf);
int now = root;
for (int i = 0; i < len; i++) {
int id = idx(buf[i]);
if (next[now][id] == -1)
next[now][id] = newnode();
now = next[now][id];
end[now] = i + 1;
vis[now] = false;
}
}
void build() {
queue <int> Q;
fail[root] = root;
for (int i = 0; i < 26; i++) {
if (next[root][i] == -1)
next[root][i] = root;
else {
fail[next[root][i]] = root;
Q.push(next[root][i]);
}
}
while (!Q.empty()) {
int now = Q.front(); Q.pop();
for (int i = 0; i < 26; i++) {
if (next[now][i] == -1)
next[now][i] = next[fail[now]][i];
else {
fail[next[now][i]] = next[fail[now]][i];
Q.push(next[now][i]);
}
}
}
}
int query(char *s, int ls, char *t, int lt) {
int now = root, res = 0;
for (int i = 0; i < ls; i++) {
int id = idx(s[i]);
now = next[now][id];
int tmp = now;
while (tmp != root) {
vis[tmp] = true;
tmp = fail[tmp];
}
}
now = root;
for (int i = 0; i < lt; i++) {
int id = idx(t[i]);
now = next[now][id];
int tmp = now;
while (tmp != root) {
if (vis[tmp]) res = max(res, end[tmp]);
tmp = fail[tmp];
}
}
now = root;
for (int i = 0; i < ls; i++) {
int id = idx(s[i]);
now = next[now][id];
int tmp = now;
while (tmp != root) {
vis[tmp] = false;
tmp = fail[tmp];
}
}
return res;
}
} ac;
string s[MAXN];
int len[MAXN];
char s1[MAXN], s2[MAXN];
int main() {
//freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while (T--) {
int n, m;
scanf("%d", &n);
ac.init();
for (int i = 1; i <= n; i++) {
cin >> s[i];
len[i] = s[i].length();
strcpy(s1, s[i].c_str());
ac.insert(s1);
}
ac.build();
/*for (int i = 0; i < ac.sz; i++)
cout << i << " " << ac.end[i] << endl;*/
scanf("%d", &m);
while (m--) {
int x, y;
scanf("%d%d", &x, &y);
strcpy(s1, s[x].c_str());
strcpy(s2, s[y].c_str());
printf("%d\n", ac.query(s1, len[x], s2, len[y]));
}
}
return 0;
}