P3121 [USACO15FEB]Censoring G题解

P3121 [USACO15FEB]Censoring G
这道题很明显是一道AC自动机的题目。
可以先将AC自动机板子打出来,打出来后该如何做这到题?可以考虑暴力做法,一个while循环一直扫描,每次扫描到了直接删除,但很明显,这样是会超时的。
通过标签观察我们发现,重新出现的单词是跟前面的部分没有关系的,那么我们就可以用栈来维护,一个栈来维护没有被删除的字符,另一个栈来维护AC自动机的下标
代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N = 1e6 + 5, INF = 0x3f3f3f3f;

char str[N], s[N];
int tr[N][26], idx, cnt[N], net[N], len[N];
int stk1[N], stk2[N], top;
queue<int> q;

void insert()
{
    int p = 0;
    for (int i = 0; str[i]; i++)
    {
        int t = str[i] - 'a';
        if (!tr[p][t])
            tr[p][t] = ++idx;
        p = tr[p][t];
    }
    cnt[p] = strlen(str);
}

void build()
{
    for (int i = 0; i < 26; i++)
        if (tr[0][i])
            q.push(tr[0][i]);
    while (!q.empty())
    {
        int t = q.front();
        q.pop();
        for (int i = 0; i < 26; i++)
        {
            int p = tr[t][i];
            if (!p)
                tr[t][i] = tr[net[t]][i];
            else 
            {
                net[p] = tr[net[t]][i];
                q.push(p);
            }
        }
    }
}  

int main()
{
    scanf("%s", &s);
    int n = 1;
    for (int i = 1; i <= n; i++)
    {
        scanf("%s", &str);
        insert();
    }
    build();
    for (int i = 0, j = 0; s[i]; i++)
    {
        int t = s[i] - 'a';
        j = tr[j][t];
        stk1[++top] = t;
        stk2[top] = j;
        if (cnt[j])
        {
            top -= cnt[j];
            if (!top)
                j = 0;
            else
                j = stk2[top];
        }
    }
    for (int i = 1; i <= top; i++)
        printf("%c", stk1[i] + 'a');
    return 0;
}
posted @ 2021-01-03 15:00  DSHUAIB  阅读(116)  评论(0)    收藏  举报