B3942 Censoring

爆炸入口

有一个S串和一个T串,长度均小于1,000,000,设当前串为U串,然后从前往后枚举S串一个字符一个字符往U串里添加,若U串后缀为T,则去掉这个后缀继续流程。

这道题确乎是个很好的联系kmp的题目

结合了栈的思想。通过栈保留匹配时的失配指针的位置,达到分段删除的效果,即可以通过删去中间若干个T串,使得被删去左右两端可以拼成T。

同时也因为栈,使得我们在输出的更加方便。结束时,在栈中的元素一定是无法删除的元素。而且是有序的(输入顺序,从下标小的开始),直接输出即可以。


怎么使用栈呢?

对于每一个匹配串中的字符。我们一一将其入栈,然后保留以当前元素为结束kmp的失配指针,方便我们拼接。然后继续和普通的kmp一样匹配。

每次从栈顶拿一个元素出来(一定是栈),根据已经保留的失配指针继续匹配。

匹配到时,就立马退栈。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int manx=1000100;
int stack[manx],top;
int f[manx],fail[manx];
char a[manx],b[manx];
int main()
{
	int n,m;
	scanf("%s%s",a,b);
	n=strlen(a),m=strlen(b);
	int k=0;
	for(int i=1;i<m;i++)
	{
		while(k&&b[i]!=b[k])	k=fail[k];
		if(b[i]==b[k])	fail[i+1]=++k;//处理失配指针
	}
	for(int i=0;i<n;i++)//一样的匹配
	{
		k=f[stack[top]];//每次从栈顶拿一个元素,因为第一个元素是0,所以说我就没有写将0入栈
		while(k&&a[i]!=b[k])	k=fail[k];//跳失配
		if(a[i]==b[k])	++k;
		if(k==m)	top-=(m-1);//匹配到时,退栈,一定要处理好退栈的元素个数,我这里i还没有入栈,所以只退栈m-1个元素
		else	f[i]=k,stack[++top]=i;//保留fail,进栈
	}
	for(int i=1;i<=top;i++)
		printf("%c",a[stack[i]]);//输出
}
原文地址:https://www.cnblogs.com/Lance1ot/p/9224173.html