关闭

[JZOJ 3427] 归途与征程

标签: dp模拟KMP
282人阅读 评论(0) 收藏 举报
分类:

Description

对于100%的测试点,1<=N<=100,1<=M<=100000。

Analysis

我们可以把A串视为一些串中间隔着一些星号。
显然,A串头尾都没有星号是有星号的特殊情况。因为无星号可以跳过头尾的串变成头尾都是星号。
下图,上者A,下者B。

我们可以对于A串中的小串与B串做一次KMP,搞一个bz[i][j]表示第i个小串是否能与B的第j个位置往后相应长度匹配。再搞一个f[i][j]表示第j个位置及其右边的第一个能与A串的i小串相匹配的位置。这样一直跳,跳,跳即可。时间复杂度是O(nm)的。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,b,a) for(int i=b;i>=a;i--)
using namespace std;
const int N=110,M=200010;
int n,m,len,num,next[N],f[N][M],c[N];
char a[N],b[M],s[N];
bool p1,pn,bz[N][M];
void kmp(int st)
{
    int j=0;
    fo(i,2,n)
    {
        while(j && s[i]!=s[j+1]) j=next[j];
        next[i]=s[i]==s[j+1]?(++j):(j=0);
    }
    j=0;
    fo(i,2,m*2)
    {
        while(j && b[i]!=s[j+1]) j=next[j];
        if(b[i]==s[j+1]) j++;
        if(j==c[st]) bz[st][i-j+1]=1;
    }
    f[st][m*2+1]=m*2+1;
    fd(j,m*2,1)
        if(bz[st][j]) f[st][j]=j;
        else f[st][j]=f[st][j+1];
}
bool match(int x)
{
    int y=x+m-1,l=1,r=num;
    if(!p1)
    {
        if(!bz[l][x]) return 0;
        x+=c[l++];
    }
    if(!pn)
    {
        if(!bz[r][y-c[r]+1]) return 0;
        y-=c[r--];
    }
    for(;l<=r;l++)
    {
        x=f[l][x];
        if(x>y) return 0;
        x+=c[l]-1;
    }
    if(x>y) return 0;
    return 1;
}
int main()
{
    scanf("%s\n%s",a+1,b+1);
    n=strlen(a+1),m=strlen(b+1);
    p1=a[1]=='*',pn=a[n]=='*';
    fo(i,m+1,m*2) b[i]=b[i-m];
    int i=0;
    while(++i<=n)
    {
        int len=0;
        for(;i<=n && a[i]!='*';i++) s[++len]=a[i];
        if(!len) continue;
        c[++num]=len;
        kmp(num);
    }
    int ans=0;
    fo(i,1,m)
        if(match(i)) ans++;
    printf("%d",ans);
    return 0;
}
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:66328次
    • 积分:3618
    • 等级:
    • 排名:第9048名
    • 原创:278篇
    • 转载:4篇
    • 译文:0篇
    • 评论:27条
    公告
    bzoj3110
    最新评论
    文章分类