牛客多校第8场F Typing practice

改题面以后就是很裸的对4个字符串kmp了,一开始板子写错了,WA20%,然后改对后是kmpTLE80%,后来发现这个字符串匹配不是普通的字符串,比如s数组为aaaaaab-b-b-,t数组是aaaaaaaa,那么每次加入一个b字母,j=nxt[u][j]就要不停地调到0,这样复杂度会退化为tlen*slen.....普通字符串不会是因为每次匹配出来的长度都在模式串和文本串中同时出现,而这个文本串是会减去的,就会出现问题,所有学习了一个nxtval数组的做法,是保证失败以后一定到达一个不同的字母的下一个地方。这题还可以ac自动机,然后fail链也直接跳到下一个不同的地方,不过我不太会写= =

#include<cstdio>
#include<cstring>
#define maxl 100010
#define inf 2000000001

int n,tlen[5],slen,top;
int a[maxl],nxt[5][maxl],nxtval[5][maxl],fail[5][maxl];
char t[5][maxl],s[maxl],ans[20];

inline void prework()
{
	for(register int i=1;i<=n;++i)
	{
		scanf("%s",t[i]+1);
		tlen[i]=strlen(t[i]+1);
	}
	slen=0;
	scanf("%s",s+1); slen=strlen(s+1); 
	for(register int u=1;u<=n;++u)
	{		
		int i=1,j=0;
		nxtval[u][1]=0;
		while(i<=tlen[u])
		{
			if(j==0 || t[u][i]==t[u][j])
			{
				++i;++j;
				if(t[u][i]==t[u][j])
					nxtval[u][i]=nxtval[u][j];
				else
					nxtval[u][i]=j;
			}
			else
				j=nxtval[u][j];
		}
	}
}

inline void mainwork()
{
	int mini=inf;
	for(register int u=1;u<=n;++u)
		fail[u][0]=0;
	for(register int u=1;u<=n;++u)
		if(mini>tlen[u]-fail[u][0])mini=tlen[u]-fail[u][0];
	printf("%d\n",mini);
	
	int j;top=0;
	for(register int i=1;i<=slen;++i)
	{
		if(s[i]=='-')
		{
			if(top>0)
			{
				a[top]=0;top--;
				for(register int u=1;u<=n;++u)
					fail[u][i]=fail[u][a[top]];
			}
			else
				for(register int u=1;u<=n;++u)
					fail[u][i]=0;
		}
		else
		{
			a[++top]=i;
			for(register int u=1;u<=n;++u)
			{
				j=fail[u][i-1]+1;
				if(t[u][j]!=s[i])
					while((j && t[u][j]!=s[i]) || (j==tlen[u]))
						j=nxtval[u][j];
				fail[u][i]=j;
			}
		}
		mini=inf;
		for(register int u=1;u<=n;++u)
			if(mini>tlen[u]-fail[u][i])mini=tlen[u]-fail[u][i];
		printf("%d\n",mini);
	}
}

int main()
{
	while(~scanf("%d",&n))
	{
		prework();
		mainwork();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/81749769