【JZOJ4624】字符串匹配

Description

这里写图片描述

Solution

诶,这题不是赤裸裸kmp吗?

对于 |S|<|T| 的情况,直接做kmp,统计答案就行。

那对于普遍情况呢?

我们先复制 T 串使得|S|<|T|,记这时有 k T串,然后跑一次kmp,得出的答案记为 a1 ,再复制一段 T ,跑一次kmp,得出的答案记为a2,那么我们很容易求出在此基础上每复制一段所增加的匹配数就为 (a2a1) ,总匹配数就为: a1+(a2a1)(nk)

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 100001
#define ll long long
using namespace std;
int f[N];
char s[N],T[N*4];
int l1,l2,l3;
void get()
{
    int j=0;
    fo(i,2,strlen(s+1))
    {
        while(j>0 && s[j+1]!=s[i]) j=f[j];
        if (s[j+1]==s[i]) j++;
        f[i]=j;
    }
}
int kmp(int l,int r)
{
    int j=0;
    int ans=0;
    fo(i,l,r)
    {
        while (j>0 && s[j+1]!=T[i]) j=f[j];
        if (s[j+1]==T[i]) j++;
        if (j==l1) 
        {
            ans++;
            j=f[j];
        }
    }
    return ans;
}
int main()
{
    freopen("4624.in","r",stdin);
    freopen("4624.out","w",stdout);
    ll n;
    cin>>n;
    cin>>s+1;
    cin>>T+1;
    get();
    l1=strlen(s+1),l2=strlen(T+1),l3=l2;
    n--;
    while(l3<=l1 && n)
    {
        n--;
        fo(i,l3+1,l2+l3) T[i]=T[i-l2];
        l3+=l2;
    }
    int t1=kmp(1,l3);
    fo(i,l3+1,l3+l2) T[i]=T[i-l3];
    l3+=l2;
    int t2=kmp(1,l3);
    cout<<t1*1ll+(t2-t1)*1ll*n;
}
posted @ 2016-07-14 08:35  sadstone  阅读(37)  评论(0编辑  收藏  举报