POJ 3167 Cow Patterns KMP+暴力

时空隧道


题意:
给出两个串,如果a和b匹配当且仅当ab中的每个对应位置的数字rank1和rank2相同,rank1代表当前元素前面小于他的元素个数,rank2代表当前元素前面等于他的元素个数,求出匹配串和模式串的匹配位置(开头位置)


分析:
KMP…裸的KMP…就是计算一下rank就好…
因为数字不会超过25,所以直接暴力求rank就好…正解其实是树状数组…


代码如下:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
const int maxn=100000+5,maxk=25000+5,maxs=25+5;
int n,k,s,a[2][maxn],nxt[maxk],num[2][maxn][maxs],vis[maxk];
inline int rank1(int len,int en,int id){
    int st=en-len,ans=0;
    for(int i=1;i<a[id][en];i++)
        ans+=num[id][en][i]-num[id][st][i];
    return ans;
}
inline int rank2(int len,int en,int id){
    return num[id][en][a[id][en]]-num[id][en-len][a[id][en]];
}
inline void getnext(void){
    nxt[0]=nxt[1]=0;int p;
    for(int i=1;i<k;i++){
        p=nxt[i];int a=rank1(p+1,p+1,1),b=rank1(p+1,i+1,1),c=rank2(p+1,p+1,1),d=rank2(p+1,i+1,1);
        while(p&&(a!=b||c!=d))
            p=nxt[p],a=rank1(p+1,p+1,1),b=rank1(p+1,i+1,1),c=rank2(p+1,p+1,1),d=rank2(p+1,i+1,1);
        if(rank1(p+1,p+1,1)==rank1(p+1,i+1,1)&&rank2(p+1,p+1,1)==rank2(p+1,i+1,1))
            nxt[i+1]=p+1;
        else
            nxt[i+1]=0;
    }
}
inline void kmp(void){
    int posa=1,posb=1,ans=0,stk[maxn];
    while(posa<=n){
        if(rank1(posb,posa,0)==rank1(posb,posb,1)&&rank2(posb,posa,0)==rank2(posb,posb,1))
            posa++,posb++;
        else if(posb==1)
            posa++;
        else
            posb=nxt[posb-1]+1;
        if(posb==k+1)
            stk[++ans]=posa-k,posb=nxt[posb-1]+1;
    }
    cout<<ans<<endl;
    for(int i=1;i<=ans;i++)
        cout<<stk[i]<<endl;
}
signed main(void){
    scanf("%d%d%d",&n,&k,&s);memset(num,0,sizeof(num));
    for(int i=1;i<=n;i++)
        scanf("%d",&a[0][i]),num[0][i][a[0][i]]=1;
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=s;j++)
            num[0][i][j]+=num[0][i-1][j];
    for(int i=1;i<=k;i++)
        scanf("%d",&a[1][i]),num[1][i][a[1][i]]=1;
    for(int i=1;i<=k;i++)
        for(int j=1;j<=s;j++)
            num[1][i][j]+=num[1][i-1][j];
    getnext();kmp();
    return 0;
}

by >_< NeighThorn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值