AC自动机好题,恐怕出题人都完全没有想到是AC自动机。
队友在写这题的时候突然发现了AC自动机的题解。
我看了一下发现还真是板子题。

正文:

WTM!!!!想打人!!!!!!!!!

Shit!!!

淦,再也不为了缩行偷懒了

这题我真的写了好久,今天刚刚发现错误,真的真的真的就是一个板子题,不过要转换一下并且check一下长度就可以了。
但是!!我为了偷懒,在输出的时候,就把答案清零了,这就导致了相同前后缀的答案错误!!!

题意:
给你很多字符串。再给你多组前后缀,问这几组前后缀在以上字符串的出现次数。

思路:
将前缀prefix 与 后缀 suffix 通过一个非字母字符连接,插入到trie中。
再将模式串通过相同的非字母字符连接,对其跑一边AC 自动机记录一下答案就可以了。

需要注意的地方就是模式串的长度不能小于后缀+前缀。

AC Code

#include <bits/stdc++.h>

using namespace std;

const int max_n = 5e5 + 10;
const int max_c = 27;

int ans[max_n], mp[max_n];

struct Aho {
    int next[max_n][max_c], fail[max_n];
    int limit[max_n];
    int root, size;
    queue<int> que;

    int newNode()
    {
        for (int i = 0; i < max_c; i++)
            next[size][i] = 0;
        limit[size++] = 0;
        return size - 1;
    }

    void init()
    {
        size = 1;
        root = newNode();
    }

    int insert(char str[])
    {
        int len = strlen(str), now = root;
        for (int i = 0; i < len; i++) {
            int c = str[i] - 'a';
            if (!next[now][c])
                next[now][c] = newNode();
            now = next[now][c];
        }
        limit[now] = len - 1;
        return now;
    }

    void build()
    {
        fail[root] = root;
        for (int i = 0; i < max_c; i++)
            if (!next[root][i])
                next[root][i] = root;
            else {
                fail[next[root][i]] = root;
                que.push(next[root][i]);
            }
        while (!que.empty()) {
            int now = que.front();
            que.pop();
            for (int i = 0; i < max_c; i++)
                if (!next[now][i])
                    next[now][i] = next[fail[now]][i];
                else {
                    fail[next[now][i]] = next[fail[now]][i];
                    que.push(next[now][i]);
                }
        }
    }

    void query(char str[], int len)
    {
        int now = root;
        for (int i = 0; str[i]; i++) {
            now = next[now][str[i] - 'a'];
            int cur = now;
            while (cur != root) {
                if (limit[cur] && len >= limit[cur])
                    ans[cur]++;
                cur = fail[cur];
            }
        }
    }
} aho;

char str[max_n], prefix[max_n], suffix[max_n];
pair<int, int> key[max_n];

int main()
{
    int T, n, m;
    scanf("%d", &T);
    while (T--) {
        memset(ans, 0, sizeof ans);
        scanf("%d %d", &n, &m);
        int cur = 0;
        for (int i = 1; i <= n; i++) {
            scanf("%s", str + cur);
            key[i] = make_pair(cur, strlen(str + cur));
            cur += key[i].second;
        }
        aho.init();
        for (int i = 1; i <= m; i++) {
            scanf("%s %s", prefix + 1, suffix);
            prefix[0] = '{';
            strcat(suffix, prefix);
            mp[i] = aho.insert(suffix);
        }
        aho.build();
        for (int i = 1; i <= n; i++) {
            int st = key[i].first, en = st + key[i].second;
            for (int j = st; j <= en; j++)
                prefix[j - st] = suffix[j - st] = str[j];
            prefix[key[i].second] = suffix[key[i].second] = 0;
            strcat(prefix, "{");
            strcat(prefix, suffix);
            aho.query(prefix, key[i].second);
        }
        for (int i = 1; i <= m; i++)
            printf("%d\n", ans[mp[i]]); //我在这里给ans清零了……
    }
    return 0;
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注

Related Posts

AC自动机

ZOJ 3228 Searching the String

AC自动机吼题 虽然是很常规的模式串与匹配串的匹配计数问题,但它稍微给 Read more…

AC自动机

HDU 2296 Ring

AC自动机+带权字符串DP 题目本身不是很难,但在处理上有点繁琐。 题 Read more…

AC自动机

POJ 1699 Best Sequence

AC自动机+spfa最短路 啊啊,明明AC自动机还有最后一题,今晚怕是 Read more…