分析

我们对于字串匹配,考虑 自动机。但是 对于删除操作不太好维护。所以我们考虑原串在 自动机上匹配。用栈保存路径,如果一旦发现该节点有一个标记,那么我们就往后退 步,之后继续匹配,直到原串匹配完毕,总的时间复杂度为

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 5e6 + 100;
int fail[N],ch[N][26],XZC[N],size,n;
char S[N],T[N],ans[N];
int top,son[N];
void insert(char *s) {
    int u = 0,len = strlen(s);
    for(int i = 0;i < len;i++) {
        int c = s[i] - 'a';
        if(!ch[u][c]) ch[u][c] = ++size;
        u = ch[u][c];
    }
    XZC[u] = max(XZC[u],len);
}
void build() {
    queue<int> q;
    for(int i = 0;i < 26;i++) if(ch[0][i]) q.push(ch[0][i]);
    while(!q.empty()) {
        int u = q.front();q.pop();
        for(int i = 0;i < 26;i++) {
            int v = ch[u][i];
            if(v) {
                fail[v] = ch[fail[u]][i];q.push(v);
                //f[v] |= f[ch[fail[u]][i]];
            }
            else ch[u][i] = ch[fail[u]][i];
        }
    }
    //for(int i = 1;i <= size;i++) cout << fail[i] << " " << f[i] << XZCl;
}
void match(char *s) {
    int u = 0;int len = strlen(s+1);
    for(int i = 1;i <= len;i++) {
        int c = s[i] - 'a';
        ans[++top] = s[i];son[top] = ch[u][c];
        if(ch[u][c]) u = ch[u][c];
        else u = 0;
        if(XZC[u]) {
            top -= XZC[u];
            u = son[top]; 
        }
    }
}
int main() {
    scanf("%s%d",S + 1,&n);
    for(int i = 1;i <= n;i++) {
        scanf("%s",T);insert(T);
    }
    build();
    match(S);
    for(int i = 1;i <= top;i++) printf("%c",ans[i]);
    return 0;
}