【YBTOJ】【Luogu P3121】[USACO15FEB]Censoring G

链接:

洛谷

题目大意:

【Luogu P4824】[USACO15FEB]Censoring S的强化版。

\(S\) 中从头开始寻找屏蔽词,一旦找到一个屏蔽词,就删除它,然后又从头开始寻找(而不是接着往下找)。

\(n\) 个屏蔽词。

正文:

多模式串匹配,考虑用 AC 自动机。详见弱化版。

但是按朴素算法直接跳失配指针的话,复杂度就假了。所以还是建 fail 树然后跑 DFS。然后因为 trie 树的存储方式本来就很链表,所以不需用多余的维护。

代码:

inline ll Read()
{
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

int n; 
char s[N], t[N], ans[N]; 

namespace AC
{
	int t[N][30], val[N], cnt[N], fail[N], Len[N], stk[N], a[N];
	int tot;
	void Insert(char *s, int I)
	{
		int p = 0, len = strlen(s);
		Len[I] = len;
		for (int i = 0; i < len; i++)
		{
			int ch = s[i] - 'a';
			if (!t[p][ch]) t[p][ch] = ++tot;
			p = t[p][ch];
		}
		val[p] = I;
	}
	queue <int> q;
	vector <int> e[N];
	void Build()
	{
		while(!q.empty()) q.pop();
		for (int i = 0; i < 26; i++)
			if (t[0][i]) q.push(t[0][i]);
		while (!q.empty())
		{
			int p = q.front(); q.pop();
			for (int i = 0; i < 26; i++)
				if (t[p][i])
					fail[t[p][i]] = t[fail[p]][i], q.push(t[p][i]);
				else
					t[p][i] = t[fail[p]][i];
		}
		for (int i = 1; i <= tot; i++)
			e[fail[i]].push_back(i);
	}
	void DFS(int u)
	{
		for (int i = 0; i < e[u].size(); i++)
		{
			int v = e[u][i];
			if (val[u]) val[v] = val[u];
			DFS(v);
		}
	}
	void Query(char *s)
	{
		int p = 0, len = strlen(s), top = 0, m = 0;
		for (int i = 0; i < len; i++)
		{
			p = t[p][s[i] - 'a'];
			if (val[p]) a[i] = Len[val[p]], top -= Len[val[p]] - 1, p = stk[top];
			else stk[++top] = p;
		}
		for (int i = len - 1, Dlt = 0; ~i; i--)
		{
			Dlt += a[i];
			if (Dlt) Dlt--;
			else ans[m++] = s[i];
		}
		for (int i = m - 1; ~i; i--) printf("%c", ans[i]);
	}
}


int main()
{
	scanf("%s", t);
	n = Read();
	for (int i = 1; i <= n; i++)
		scanf ("%s", s), AC::Insert(s, i);
	AC::Build();
	AC::DFS(0);
	AC::Query(t);
	return 0;
}
posted @ 2021-06-02 17:24  Jayun  阅读(53)  评论(0编辑  收藏  举报