链接: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.
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<b;i++)
const int maxn=1e5+100;
char s[4][maxn];
char str[maxn];
int fail[maxn],f[maxn];
void getFail(char *P,int len)
{
fail[0] = fail[1] = 0; //压缩路径的失配指针
f[0]=f[1]=0; //正常的失配指针,也就是[0,i-1]的最大前缀后缀
for(int i = 1; i < len; i++)
{
int j = f[i];
while(j && P[i] != P[j] ) j = f[j];//没有可匹配,或者能找到匹配的P[j] ==T[i]
fail[i+1] = f[i + 1] = (P[i] == P[j]) ? j + 1 : 0;
//既然i+1的失配位置指向j+1,但是P[i+1]和P[j+1]的内容是相同的
//所以就算指针从i+1跳到j+1去,还是不能匹配,所以f[i+1]直接=f[j+1]
if(fail[i+1]==j+1 && P[i+1]==P[j+1]) fail[i+1]=fail[j+1];
}
}
int sum=maxn;
int len;
int ans[maxn],stk[maxn];//stk[i]的意思是 [0,i]的文本串和 模式串的最大匹配长度(对应的j)
/*
为什么要使用真正的KMP?
考虑模版串是 aaaaaaaaaaaaaaa....,如果这样超级长,
而且文本串是 这种 aaaaaaaaaaaaabaaaaaaaaaab....就是好不容易j跳到了末尾,然后不匹配又得一个一个的跳回来
所以这样就会非常浪费时间,如果压缩了的话,就会发现直接回到0
比如ABABC, 事实上,如果和第二个B不匹配的话,和第一个B也完全不会匹配,因为他们两个串相等,也就是AB AB,所以可以直接跳回第一个B失配的位置。
00012
*/
void solve(char* T,char* P,int num){
int m = strlen(P);
sum=min(sum,m);
getFail(P,m);
int j=0,top = -1;
for(int i = 0;i < len; ++i){
if(str[i]=='-'){
if(top>-1)--top;
j=top==-1?0:stk[top]; //对于退回来的时候的 j 的赋值比较难理解,其实还是[0,top]的最大匹配长度,同时也是和 文本串 stk[top+1] 比较的 模版串的j号下标的字符,也就是为下一个字符比较做好准备
}
else{
while(j&&T[i]!=P[j])j=fail[j];
if(T[i]==P[j])++j;
stk[++top]=j;
}
ans[i]=min(ans[i],m-j);//j是存在的文本串和模版串的最大匹配长度
}
}
int main(){
int n;
scanf("%d",&n);
rep(i,0,n)scanf("%s",s[i]);
scanf("%s",str);
len=strlen(str);
fill(ans,ans+len,maxn);
rep(i,0,n) solve(str,s[i],i);
printf("%d\n",sum);
rep(i,0,len)printf("%d\n",ans[i]);
return 0;
}