版权声明:欢迎转载蒟蒻博客,但请注明出处: https://blog.csdn.net/LPA20020220/article/details/84193028
洛谷传送门
BZOJ传送门
题目描述
FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过 的字符串 。他有一个包含 个单词的列表,列表里的 个单词记为 。他希望从 中删除这些单词。
FJ每次在 中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从 中删除这个单词。他重复这个操作直到 中没有列表里的单词为止。注意删除一个单词后可能会导致 中出现另一个列表中的单词
FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在 中出现的开始位置是互不相同的
请帮助FJ完成这些操作并输出最后的
输入输出格式
输入格式:
第一行一个字符串 。
第二行一个正整数 。
以下 行, 每行一个字符串, 表示 , 长度总和不超过 。
输出格式:
一行一个字符串, 表示删除操作完成后的 。
输入输出样例
输入样例#1:
begintheescapexecutionatthebreakofdawn
2
escape
execution
输出样例#1:
beginthatthebreakofdawn
解题分析
对模板串建立 自动机, 然后把匹配串跑一遍,用栈记录位置即可。
代码如下:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cctype>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 100500
int fail[MX], l[MX], pos[MX];
int son[MX][26];
char mod[MX], dat[MX], sta[MX];
int n, root, ct, top;
std::queue <int> q;
IN void insert(char *str)
{
int len = std::strlen(str);
R int now = root, id;
for (R int i = 0; i < len; ++i)
{
id = str[i] - 'a';
if (!son[now][id]) son[now][id] = ++ct;
now = son[now][id];
}
l[now] = len;
}
IN void build()
{
R int now;
for (R int i = 0; i < 26; ++i) if (son[root][i]) q.push(son[root][i]);
W (!q.empty())
{
now = q.front(); q.pop();
for (R int i = 0; i < 26; ++i) if (son[now][i]) fail[son[now][i]] = son[fail[now]][i], q.push(son[now][i]);
else son[now][i] = son[fail[now]][i];
}
}
IN void solve(char *str)
{
int len = std::strlen(str);
R int now = root, id;
for (R int i = 0; i < len; ++i)
{
id = str[i] - 'a';
now = son[now][id];
sta[++top] = str[i], pos[top] = now;
W (l[now])
{
top -= l[now];
now = pos[top];
}
}
for (R int i = 1; i <= top; ++i) printf("%c", sta[i]); puts("");
}
int main(void)
{
scanf("%s%d", dat, &n);
for (R int i = 1; i <= n; ++i)
{
scanf("%s", mod);
insert(mod);
}
build();
solve(dat);
}