POJ-3167- Cow Patterns(KMP)


Cow Patterns
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 4184 Accepted: 1496


Sample Input

9 6 10
5
6
2
10
10
7
3
2
9
1
4
4
3
2
1

Sample Output

1
3




题目大意:给定数串A(母串),数串B(子串),在A中寻找与B串符合特性匹配的开始位置,并输出个数与位置,

                  例如:模式串1 4 4 2 3 1,主串5 6 2 10 10 7 3 2 9

                                  那么2 10 10 7 3 2 就是匹配的。 

问题分析:匹配特性:若当前位置匹配,则需满足 之前1-比当前数小 2-比当前数相等  的数的个数相等 ,

                                根据特性得到模式串的next数组,后对主串进行匹配,可用KMP算法实现。


CODE:


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <vector>
#define MAXN 100005
#define MAXM 25005
using namespace std;
int n,m,s,sum;
int a[MAXN],b[MAXM],ans[MAXN];
int as[MAXN][27],bs[MAXM][27];
int next[MAXM];
void init()
{
    for(int j=1; j<=25; ++j)
    {
        as[0][j]=0;
        bs[0][j]=0;
    }
    bs[0][b[0]]++;
    as[0][a[0]]++;
    for(int i=1; i<n; ++i)
    {
        for(int j=1; j<=25; ++j)
            as[i][j]=as[i-1][j];
        as[i][a[i]]++;
    }
    for(int i=1; i<m; ++i)
    {
        for(int j=1; j<=25; ++j)
            bs[i][j]=bs[i-1][j];
        bs[i][b[i]]++;
    }
}
void kmp()
{
    int i,j,x,xx,y,yy;
    next[0]=j=-1;
    i=0;
    while(i<m)
    {
        x=xx=y=yy=0;
        if(j>-1)
        {
            for(int k=1; k<b[i]; ++k)
                x+=bs[i][k]-bs[i-j-1][k];
            for(int k=1; k<b[j]; ++k)
                y+=bs[j][k];
            xx=bs[i][b[i]]-bs[i-j-1][b[i]];
            yy=bs[j][b[j]];
        }
        if(j==-1 ||(x==y&&xx==yy))
            next[++i]=++j;
        else j=next[j];
    }
}
void kmp_per()
{
    int i,j,x,xx,y,yy;
    i=j=0;
    while(i<n)
    {
        x=xx=y=yy=0;
        if(j!=-1)
        {
            for(int k=1; k<a[i]; ++k)
            {
                if(i>j)
                    x+=as[i][k]-as[i-j-1][k];
                else x+=as[i][k];
            }
            for(int k=1; k<b[j]; ++k)
                y+=bs[j][k];
            if(i>j)
                xx=as[i][a[i]]-as[i-j-1][a[i]];
            else xx=as[i][a[i]];
            yy=bs[j][b[j]];
        }
        if(j==-1 || (x==y&&xx==yy))
        {
            ++i;
            ++j;
            if(j>=m)
            {
                ans[sum++]=i-m+1;
                j=next[j];
            }
        }
        else j=next[j];
    }
}
int main()
{
    while(scanf("%d%d%d",&n,&m,&s)!=EOF)
    {
        for(int i=0; i<n; ++i)
            scanf("%d",a+i);
        for(int i=0; i<m; ++i)
            scanf("%d",b+i);
        sum=0;
        init();
        kmp();
        kmp_per();
        printf("%d\n",sum);
        for(int i=0; i<sum; ++i)
            printf("%d\n",ans[i]);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值