hdu5918-Sequence I (kmp)

题目来源:http://./showproblem.php?pid=5918

题意

给出一个a序列,b序列,然后问在a序列中有多少个b序列,并且是以下形式:
b1,b2,⋯,bmb1,b2,⋯,bm is exactly the sequence aq,aq+p,aq+2p,⋯,aq+(m−1)paq,aq+p,aq+2p,⋯,aq+(m−1)p where q+(m−1)p≤nq+(m−1)p≤n and q≥1。

思路

按照最暴力的方法,枚举一个个位置,从左至右,共n-(m-1)*p个。
但是极限数据会是O(n²)的时间复杂度,需要优化。
想到了kmp,手打一套,记一下数,就可以了。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=1e6+10;
LL a[maxn],b[maxn],nexx[maxn];
int n,m,p;
void next_()
{
    memset(nexx,0,sizeof(nexx));
    int j=-1,i=0;
    nexx[0]=-1;
    while(i<m)
    {
        if(j==-1||b[j]==b[i])
        {
            nexx[++i]=++j;
        }
        else
        j=nexx[j];
    }
}
int kmp_(int pos)
{
    int i=pos,j=0,ans=0;
    while(i<n&&j<m)
    {
        if(j==-1||a[i]==b[j])
        {
            i+=p;
            j++;
        }
        else
           j=nexx[j];
        if(j>=m)
        {
            ans++;
            j=nexx[j];
        }
    }
    return ans;
}
int main()
{
    int T,cases=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&p);
        for(int i=0; i<n; i++)
            scanf("%lld",&a[i]);
        for(int i=0; i<m; i++)
            scanf("%lld",&b[i]);
        next_();
        int res=n-(m-1)*p;
        int ans=0;
        for(int i=0; i<p&&i<res; i++)
        {
            ans+=kmp_(i);
        }
        printf("Case #%d: %d\n",cases++,ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值