Typing practice

链接: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];

/*
1.初始化的问题
还是想状态机,第一个字符,之前没有任何字符,所以文本串当前后缀和模版串前缀 最大匹配长度是0

2.'-'之后我们的初始化,有问题么
考虑空串,前面还是没有字符,等同上面

3.为什么要使用真正的KMP
考虑模版串是 aaaaaaaaaaaaaaa....,如果这样超级长,
而且文本串是 这种 aaaaaaaaaaaaabaaaaaaaaaab....就是好不容易j跳到了末尾,然后不匹配又得一个一个的跳回来
所以这样就会非常浪费时间,如果压缩了的话,就会发现直接回到0
比如ABABC, 事实上,如果和第二个B不匹配的话,和第一个B也完全没有必要匹配,因为他们两个相等,也就是AB AB,所以可以直接跳回0
    00012
*/

void solve(char* T,char* P,int num){
    int m = strlen(P);
    sum=min(sum,m);
    getFail(P,m);
    
    int j=0,top = 0;
    stk[0]=0;
    for(int i =  0;i < len; ++i)
    {
        if(T[i] == '-'){
            if(top>0) top--;
            j = stk[top];//j就是 -1 之后那个位置的后缀和 模版串前缀的最大匹配长度,也就是要转移的位置
        }
        else
        {
          while(j&&P[j] != T[i]) j = fail[j];//失配转移到对应的下标
          if(P[j] == T[i]) ++j;//和文本串当前后缀匹配的最大长度,从1开始,所以正好是位置+1,也正好是[0,i+1]已经匹配的长度
          stk[++top] = j;//所以(top+1) 失配的话会转移到j,(因为[0,j-1]是和 [top-j+1,top]匹配的)
        }
        ans[i]=min(ans[i],m-stk[top]);
    }
}

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;
}

猜你喜欢

转载自blog.csdn.net/qq_36424540/article/details/81776715