牛客网暑期ACM多校训练营(第九场)F:Typing practice(优化后的KMP)

链接:https://www.nowcoder.com/acm/contest/147/F

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
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.

思路:这题可以用KMP来做,但是求next数组时需要优化,因为一般字符串匹配中失配后,就会利用next数组不断往会跳。
但在这题中有删除符’-‘,可能会导致不断的失配。
例如:
S=aaaaaaaa
T=aaaaaaab-c-d-e-f-h-…..
当S匹配到T中的字符‘b’时,就需要利用next数组往回跳,碰到‘-‘‘b’删除后又碰到‘d’,也会不断往会跳,同理碰到‘e’,’f’,’h’……….
这样的话复杂度就很高了,所以需要优化next数组,当碰到相同字符时,next数组需要指向更前的一个位置。

#include<bits/stdc++.h>
using namespace std;
const int MAX=2e5+10;
const int INF=1e9+7;
typedef long long ll;
int f[MAX];         //正常fail数组
int nex[MAX];       //优化后的fail数组
void getfail(char *s,int n)
{
    f[0]=f[1]=0;
    nex[0]=nex[1]=0;
    for(int i=1;i<n;i++)
    {
        int j=f[i];
        while(j&&s[i]!=s[j])j=f[j];
        f[i+1]=nex[i+1]=(s[i]==s[j]?j+1:0);
        if(nex[i+1]==j+1&&s[i+1]==s[j+1])nex[i+1]=nex[j+1];//碰到相同字符指向更前一个位置
    }
}
int ans[MAX];
stack<int>q;
void kmp(char *s,char *p,int m,int n)
{
    while(!q.empty())q.pop();q.push(0);
    ans[0]=min(ans[0],m);
    getfail(s,m);
    for(int i=0,j=0;i<n;i++)
    {
        if(p[i]=='-')
        {
            if(q.size()>1)q.pop();
            j=q.top();
        }
        else
        {
            while(j&&s[j]!=p[i])j=nex[j];
            if(s[j]==p[i])j++;
            q.push(j);
        }
        ans[i+1]=min(ans[i+1],m-q.top());
    }
}
char s[5][MAX],p[MAX];
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%s",s[i]);
    scanf("%s",p);
    int m=strlen(p);
    for(int i=0;i<=m;i++)ans[i]=INF;
    for(int i=1;i<=n;i++)kmp(s[i],p,strlen(s[i]),m);
    for(int i=0;i<=m;i++)printf("%d\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值