[Usaco2015 Feb]Censoring

Censoring

FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过10^5的字符串S。他有一个包含n个单词的列表,列表里的n个单词记为t_1...t_N。他希望从S中删除这些单词。

FJ每次在S中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从S中删除这个单词。他重复这个操作直到S中没有列表里的单词为止。注意删除一个单词后可能会导致S中出现另一个列表中的单词

FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在S中出现的开始位置是互不相同的

请帮助FJ完成这些操作并输出最后的S

给若干模式串和一个文本串.每次从文本串开头找到一个模式串,将其删去,直到无法删去为止,求出最后剩余的文本.保证任一个模式串中没有其他模式串.

jklover的题解

将模式串建成一个 AC 自动机,用一个栈来维护当前剩余的字符.匹配成功时直接修改栈顶.同时需要维护每个节点在 Trie 树上的位置.这样删除后可以立即得出当前的位置 u

时间复杂度:线性。

用栈来维护s,想法实在巧妙。

co int N=1e5+1,S=26;
int len[N];
namespace AC
{
	int idx;
	int ch[N][S],fail[N],val[N];
	
	void ins(char*s,int n,int v)
	{
		int u=0;
		for(int i=0;i<n;++i)
		{
			int k=s[i]-'a';
			if(!ch[u][k])
				ch[u][k]=++idx;
			u=ch[u][k];
		}
		val[u]=v;
	}
	
	void getfail()
	{
		std::queue<int>Q;
		for(int i=0;i<S;++i)
			if(ch[0][i])
				Q.push(ch[0][i]);
		while(Q.size())
		{
			int u=Q.front();Q.pop();
			for(int i=0;i<S;++i)
			{
				if(ch[u][i])
				{
					fail[ch[u][i]]=ch[fail[u]][i];
					Q.push(ch[u][i]);
				}
				else
					ch[u][i]=ch[fail[u]][i];
			}
		}
	}
	
	void solve(char*s,int n)
	{
		int u=0;
		char stk[N];
		int tp=0;
		int lst[N];
		for(int i=0;i<n;++i)
		{
			int k=s[i]-'a';
			stk[++tp]=s[i];
			lst[tp]=ch[u][k];
			if(val[lst[tp]])
				tp-=val[lst[tp]];
			u=lst[tp];
		}
		for(int i=1;i<=tp;++i)
			putchar(stk[i]);
		puts("");
	}
}
char buf[N];
char s[N];
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	scanf("%s",s);
	int n;
	read(n);
	for(int i=1;i<=n;++i)
	{
		scanf("%s",buf);
		int len=strlen(buf);
		AC::ins(buf,len,len);
	}
	AC::getfail();
	AC::solve(s,strlen(s));
	return 0;
}

posted on 2019-01-25 15:38  autoint  阅读(214)  评论(0编辑  收藏  举报

导航