题解 洛谷 P3121 [USACO15FEB]审查

AC自动机入门题

题目链接

开两个栈

建出trie图 , 处理完失配数组

Ac自动机扫过去 , 第一个栈记扫过的 , 第二个栈记匹配位置

然后ac自动机里面一个end记录以它为结尾单词长度

匹配到就删掉这个单词 , 即栈顶减去其长度,更新trie上当前节点  , 由于新子串仅由删去一个单词后前后拼接而成

所以now更新为原栈顶

最后答案是原文中编号在第二个栈中的字母

code:

#include <iostream>

#include <cstring>

#include <string>

#include <queue>

using namespace std;

int n;

struct node {
    int end;
    int vis[26];
    int fail;
} ac[1000001];

int sta1[1000001] , sta2[1000001];

string s;

int cnt = 0;

void insert(string s) {
    int now = 0 , l = s.length();
    for(int i = 0 ; i < l ; i++) {
        if(!ac[now].vis[s[i]-'a'])
            ac[now].vis[s[i]-'a'] = ++ cnt;
        now = ac[now].vis[s[i]-'a'];
    }
    ac[now].end = l;
}

void get_fail() {
    queue <int> q;
    for(int i = 0; i < 26; i++)
        if(ac[0].vis[i] != 0)
            q.push(ac[0].vis[i]);
    while(!q.empty()) {
        int now = q.front();
        q.pop();
        for(int i = 0; i < 26; i++) {
            if(ac[now].vis[i] != 0)
                ac[ac[now].vis[i]].fail = ac[ac[now].fail].vis[i] , q.push(ac[now].vis[i]);
            else
                ac[now].vis[i] = ac[ac[now].fail].vis[i];
        }
    }
}

int top = 0;

void solve(string s) {
    int now = 0 , l = s.length();
    for(int i = 0; i < l; i++) {
        now = ac[now].vis[s[i]-'a'];
        sta1[++top] = now;
        sta2[top] = i;
        if(ac[now].end) {
            top -= ac[now].end;
            if(!top)
                now = 0;
            else
                now  = sta1[top];
        }

    }
}

int main() {
    cin >> s;
    cin >> n;
    for(int i = 1; i <= n; i++) {
        string in;
        cin >> in;
        insert(in);
    }
    get_fail();
    solve(s);
    for(int i = 1; i <= top; i++)
        cout << s[sta2[i]] ;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/treap/p/12201085.html