zoukankan      html  css  js  c++  java
  • [洛谷P3121] 审查(黄金) (AC自动机)

    题目描述

    FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过10^5的字符串S。他有一个包含n个单词的列表,列表里的n个单词记为t_1...t_N。他希望从S中删除这些单词。

    FJ每次在S中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从S中删除这个单词。他重复这个操作直到S中没有列表里的单词为止。注意删除一个单词后可能会导致S中出现另一个列表中的单词

    FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在S中出现的开始位置是互不相同的

    请帮助FJ完成这些操作并输出最后的S

    输入输出格式

    Input

    第一行包含S.
    第二行包含N,即审查出来的单词的数量。
    接下来的N行包含字符串t1…tn。每个字符串将只包含小写字母(范围在a...z),并且所有这些字符串的组合长度将最多是10^5。

    Output

    删除操作完成后形成的新的字符串S(这里保证删除过程中不会出现空串)。

    输入输出样例

    输入样例#1:

    begintheescapexecutionatthebreakofdawn
    2
    escape
    execution

    输出样例#1:

    beginthatthebreakofdawn


    题解思路

    看到多个串在一个串上匹配啊是吧,这不AC自动机模板(巨难)题吗。
    不过我们是要删除串啊,怎么考虑去删掉这些串呢?

    首先这个出题人可能语文是体育老师教的,也许是我的语文是体育老师教的(逃
    最早出现的列表中的单词(最早出现指该单词的开始位置最小,这TM不是说我们删单词要一个一个按顺序删,而是说,在文本串里最早出现的一个随便哪一个模式串我们把它删掉

    然后怎么搞?

    我们考虑把不要删除的文本串一次加入一个栈中,要删掉的那个单词在匹配完成时,再从栈里面弹出之前的单词长度即可。最后输出栈

    关于AC自动机在这道题的卵用

    我们在字典树上跑文本串的时候,可能某一次文本串匹配单词时,那个字典树的节点是空的,所以用fail指针来节省时间和避免错误


    YYJ丑陋的代码系列

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int N=500001;
    struct node{
        int fail,ch[26],end;
    }t[N];
    char SS[N],ss[N],s[N];
    int S[N],top,cnt;
    void build()
    {
        int now=0,len=strlen(s);
        for(int i=0;i<len;i++)
        {
            if(!t[now].ch[s[i]-'a'])
            t[now].ch[s[i]-'a']=++cnt;
            now=t[now].ch[s[i]-'a'];
        }
        t[now].end=len;
    }
    
    void get_fail()
    {
        queue<int>q;
        for(int i=0;i<26;i++)
        if(t[0].ch[i])q.push(t[0].ch[i]);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=0;i<26;i++)
            {
                if(t[u].ch[i])
                t[t[u].ch[i]].fail=t[t[u].fail].ch[i],q.push(t[u].ch[i]);
                else t[u].ch[i]=t[t[u].fail].ch[i];
            }
        }
    }
    
    int main()
    {
        scanf("%s",ss);
        int n;scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s);
            build();
        }
        get_fail();
        int len=strlen(ss),now=0;
        for(int i=0;i<len;i++)
        {
            ++top;
            S[top]=now;
            SS[top]=ss[i];
            now=t[now].ch[ss[i]-'a'];
            if(t[now].end)
            top-=t[now].end,now=S[top+1];
        }
        for(int i=1;i<=top;i++)
        cout<<SS[i];
        return 0;
    }
    
  • 相关阅读:
    Springmvc全局异常处理
    SpringMVC异常处理一
    [GDB7] gdb 的学习
    《Python 第七章》更加抽象
    python问题:IndentationError:expected an indented block错误解决
    [C/C++] C++ 类的学习
    [GCC6] gcc 的学习
    [Python] 列表 list
    [python] 循环与轻量级 pass, del, eval
    《Python 第八章》异常
  • 原文地址:https://www.cnblogs.com/hhh1109/p/9180441.html
Copyright © 2011-2022 走看看