Never give in.

弱小和无知不是生存的障碍,傲慢才是。

[JZOJ3427]【NOIP2013模拟】归途与征程

Description

这里写图片描述

Solution

注意,这里的匹配是全部都要匹配,不能落下一个字符。

A串中,”* “将字符串分成若干个区间(不包括”*”)。
bz[i][j]表示A串中第i个区间和B串中第j位开头能否匹配
对于每一个区间,都与B串做一次KMP,可以在O(NM)的时间范围内求出bz

然后我们只需要把B串复制一遍,再枚举开头判断就好。

但是这样判断的复杂度达到O(M),总的是O(M2)

考虑优化判断。

于是可以预处理next[i][j]表示bz[i+1][k]=1大于jk最小值

这样复杂度就变成O(NM)

Code

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
int n,m,m1,num,a[101],next[101][200001];
char s1[101],s2[200001];
bool bz[101][200001];
void kmp(int ar,int lt,int rt)
{
    if (rt<lt)
    {
        int i;
        fo(i,0,m1+1) bz[ar][i]=1;
        return; 
    }
    int len=rt-lt+1,i,i1,j=0,j1=0,p[101];
    p[1]=0;
    fo(i1,2,len)
    {
        i=i1+lt-1;
        j1=j+lt-1;
        while (j>0&&s1[j1+1]!=s1[i]) 
        {
            j=p[j];
            j1=j+lt-1;
        }
        if (s1[j1+1]==s1[i]) j++;
        j1=j+lt-1;
        p[i1]=j;
    }
    j=0;
    fo(i,1,m1)
    {
        j1=j+lt-1;
        while (j>0&&s1[j1+1]!=s2[i]) 
        {
            j=p[j];
            j1=j+lt-1;
        }
        if (s1[j1+1]==s2[i]) j++;
        j1=j+lt-1;
        if (j==len) bz[ar][i-j+1]=1;
    }
}
bool pd(int st)
{
    int i=st,j=1;
    if (bz[j][st]==0) return 0; 
    a[0]=0;
    while (i!=0&&i+a[j]-a[j-1]-2<=st+m-1) 
    {
        if (j==num-1&&bz[num][st+m-a[num]+a[num-1]+1]) return 1;
        i=next[j][i+a[j]-a[j-1]-2];
        j++;
    }
    return 0; 
}
int main()
{
    scanf("%s",s1+1);
    scanf("\n");
    scanf("%s",s2+1);
    n=strlen(s1+1);
    m=strlen(s2+1);
    num=0;
    int i,j;
    fo(i,1,m-1) s2[i+m]=s2[i]; 
    m1=2*m-1;
    fo(i,1,n) if (s1[i]=='*') a[++num]=i;
    a[++num]=n+1;
    memset(bz,0,sizeof(bz));
    fo(i,1,num)
    {
        kmp(i,a[i-1]+1,a[i]-1); 
    } 
    fod(i,m1-1,0)
    {
        fo(j,0,num-1)
        {
            next[j][i]=bz[j+1][i+1]?i+1:next[j][i+1];
        }
    }
    int ans=0;
    fo(i,1,m) 
    {
        if (i==2)
        {
            n++;
            n--;
        }
        if(pd(i)) ans++;
    }
    cout<<ans;
} 
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hzj1054689699/article/details/51555067
个人分类: 题解 kmp
上一篇[JZOJ3422]【NOIP2013模拟】水叮当的舞步
下一篇神奇的线性筛法
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭