牛客网暑期ACM多校训练营(第九场)Typing practice

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37632935/article/details/81778317

链接:https://www.nowcoder.com/acm/contest/147/F
来源:牛客网
 

Niuniu is practicing typing.

Given n words, Niuniu want to input one of these. He wants to input (at the end) as few characters (without backspace) as possible,

to make at least one of the n words appears (as a suffix) in the text.

Given an operation sequence, Niuniu want to know the answer after every operation.

An operation might input a character or delete the last character.

输入描述:

The first line contains one integer n.
In the following n lines, each line contains a word.
The last line contains the operation sequence.
'-' means backspace, and will delete the last character he typed.

He may backspace when there is no characters left, and nothing will happen.

1 <= n <= 4
The total length of n words <= 100000

The length of the operation sequence <= 100000

The words and the sequence only contains lower case letter.

输出描述:

You should output L +1 integers, where L is the length of the operation sequence.

The i-th(index from 0) is the minimum characters to achieve the goal, after the first i operations.

示例1

输入

复制

2
a
bab
baa-

输出

复制

1
1
0
0
0

说明

"" he need input "a" to achieve the goal.
"b" he need input "a" to achieve the goal.
"ba" he need input nothing to achieve the goal.
"baa" he need input nothing to achieve the goal.
"ba" he need input nothing to achieve the goal.

示例2

输入

复制

1
abc
abcd

输出

复制

3
2
1
0
3

说明

suffix not substring.

思路:

先不考虑有退格的情况,我们每次的匹配都是找当前主串前i个字符组成的后缀和模式串前缀的最长公共长度。考虑kmp匹配的过程,当我们第i次匹配完成之后,那么第i+1次就是在第i次匹配的主串后面添加了一个字母。那么我们可以继续往下匹配,因为kmp模式串匹配主串时当匹配到主串第i个字符next[i]就是当前以i结尾的主串的后缀和模式串的前缀的最长公共长度,那么我们只需要继续进行匹配,每次记录下答案就行了。

当我们存在空格时,相当于把最后一个字符去掉,那我们可以让我们的模式串指针也倒退到之前不存在删掉的那个字符的状态。

只需要多开一个数组记录每次的模式串指针即可。

到这里仍然没有结束,如果使用普通的kmp,会存在aaaaaaaaaa.......aaaaab-b-b-这种情况,当我们跑到了第一个b的位置如果匹配不成功,那么我们的匹配串指针会一步一步的往回跳,跳完了之后,你再删除最后一个b然后他又会回到原来的位置。然后下一个字符是b他又会一步一步往回跳。

这是普通的kmp的nxet数组。

然后是优化过的next数组。

可以看出如果下次跳的位置的字母与当前位置的字母相同,他就不会跳到那个位置。

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f

void pre_kmp(char x[],int m,int kmpnext[])//优化后的kmp
{
	//cout<<x<<endl;
	int i,j=-1;
	j=kmpnext[0]=-1;i=0; 
	while(i<m)
	{
		while(-1!=j&&x[i]!=x[j])
		{
			j=kmpnext[j];
		}
		if(x[++i]==x[++j])
		{
			kmpnext[i]=kmpnext[j];
		}
		else kmpnext[i]=j;
	}
}
int nex[100005];int ans[100005];
int q[100005];//保存kmp历史指针 
void solve(char *s,char *a)
{
	int len=strlen(s);
	int n=strlen(a);
	pre_kmp(s,len,nex);
	int j=0,top=0;//kmp指针,当前a数组大小。 
	q[0]=0;
	for(int i=0;i<n;i++)
	{
		if(a[i]=='-')
		{
			top=max(top-1,0);
			j=q[top];			//删掉一个字符所以回到上一个指针 
		}
		else
		{
			while(j!=-1&&s[j]!=a[i]) j=nex[j];
			if(j==-1) j++;
			if(s[j]==a[i]) j++;
			q[++top]=j;
		}
		ans[i]=min(ans[i],len-j);
	}
}
char s[5][100005];char a[100005];
int main()
{
	int n;
	scanf("%d",&n);
	int p=INF;
	for(int i=1;i<=n;i++) 
	scanf("%s",s[i]);
	scanf("%s",a);
	memset(ans,INF,sizeof(ans));
	for(int i=1;i<=n;i++)
	{
		int o=strlen(s[i]);
		p=min(p,o);
		solve(s[i],a);
	}
	printf("%d\n",p);
	int m=strlen(a);
	for(int i=0;i<m;i++) printf("%d\n",ans[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37632935/article/details/81778317