HDU 6138 AC自动机

来源:互联网 发布:spss筛选数据统计 编辑:程序博客网 时间:2024/06/03 20:09

题意:

题目链接: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;}