1. 程式人生 > 實用技巧 >P3121 [USACO15FEB]Censoring G題解

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;
}