kmp优化

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

 

即做4个kmp,可持久化每增加一个字符后的match。

题外话:假如说在a串中找b串,做kmp的过程其实在不断的使b串的前缀与当前匹配到的串的后缀对齐,扫a串,每增加一个字符就更新一次match(最大匹配位置),当match为b串长度-1时,即找到了b串,更新操作均摊下来为O(1)。注意b串为ccccccccccc的情况,匹配失败,每次只会往前跳一个字符,在本题中就会成为卡时间的地方,优化加一行代码即可,见代码。

#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
 
int kmp_fail[4][100005];
char kmp_p[4][100005];
void getFail(char *P, int *fail) {
    int match = -1;
    fail[0] = -1;
    for (int i = 1; P[i]; ++i) {
        while (match >= 0 && P[match + 1] != P[i]) {              match = fail[match];
        }
        if (P[match + 1] == P[i]) {              match++;
        }
        fail[i] = match;  
        if(match!=-1&&P[i+1]==P[match+1]) fail[i] = fail[match];
        //优化:两者相等,那么i+1失配时,match+1也会失配,则可跳过 
    }
}
char s[100005];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%s",kmp_p[i]);
        getFail(kmp_p[i], kmp_fail[i]);
    }
    vector<int>vt[5];
    scanf("%s",s);
    int match[4]={-1,-1,-1,-1};
    int len[4];
    int mm=100000000;
    for(int i=0;i<n;i++) {len[i]=strlen(kmp_p[i]);mm=min(mm,len[i]);}
    printf("%d\n",mm);
    for(int i=0;s[i];i++)
    {   int mi=100000000;
        if(s[i]=='-')
        {
            for(int j=0;j<n;j++)
            {   if(vt[j].size()>0)
                {vt[j].pop_back();
                 if(vt[j].size()>0) match[j]=vt[j][vt[j].size()-1];
                    else match[j]=-1;
                  
                 
                }
            }
            if(vt[4].size()>0)
            {
            vt[4].pop_back();
            if(vt[4].size()>0) printf("%d\n",vt[4][vt[4].size()-1]);
                    else printf("%d\n",mm);
            }
            else printf("%d\n",mm);
        }
        else {
            for(int j=0;j<n;j++)
            {
                while(match[j]>=0&&kmp_p[j][match[j]+1]!=s[i])
                        match[j]=kmp_fail[j][match[j]];
                if(kmp_p[j][match[j]+1]==s[i]) match[j]++;
                mi=min(mi,len[j]-match[j]-1);
                vt[j].push_back(match[j]);
            
            }
            vt[4].push_back(mi);
            printf("%d\n",mi);
            }
    }
     
    return 0;
}

 

posted @ 2018-09-03 20:55  hzhuan  阅读(150)  评论(0编辑  收藏  举报