HDU4749 Parade Show(KMP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4749

题意:给出两个数字串A、B。问A中有多少不相交的子串a能匹配B。匹配的意思是a中任意两个位置i和j的大小关系和B的这两个位置的大小关系是一样的。

思路:若是完全一模一样的匹配的话那么KMP是很好理解的。那么对于上述的比较方式怎么比较两个串相等呢?对于a的位置i和B的位置i,我们只要比较i之前a中a[i]的个数和B中B[i]的个数是否相等,以及a中小于a[i]的个数和B中小于B[i]的数字个数是否相等。只要每个位置都满足则这两个串匹配。

 

int f[N][30],g[N][30],next[N];

int a[N],b[N],n,m,K;

int visit[N];



int ok(int x,int y)

{

    if(g[x][b[x]]!=g[y][b[y]]-g[y-x][b[y]]) return 0;

    int cnt1=0,cnt2=0,i;

    for(i=1;i<b[x];i++) cnt1+=g[x-1][i];

    for(i=1;i<b[y];i++) cnt2+=g[y-1][i];

    for(i=1;i<b[y];i++) cnt2-=g[y-x][i];

    return cnt1==cnt2;

}



void getNext()

{

    next[1]=0;

    int i,j=0;

    for(i=2;i<=m;i++)

    {

        while(j&&!ok(j+1,i)) j=next[j];

        if(ok(j+1,i)) j++;

        next[i]=j;

    }

}



int ok1(int x,int y)

{

    if(g[x][b[x]]!=f[y][a[y]]-f[y-x][a[y]]) return 0;

    int cnt1=0,cnt2=0,i;

    for(i=1;i<b[x];i++) cnt1+=g[x-1][i];

    for(i=1;i<a[y];i++) cnt2+=f[y-1][i];

    for(i=1;i<a[y];i++) cnt2-=f[y-x][i];

    return cnt1==cnt2;

}



void kmp()

{

    int i,j=0;

    for(i=1;i<=n;i++)

    {

        while(j&&!ok1(j+1,i)) j=next[j];

        if(ok1(j+1,i)) j++;

        if(j==m) visit[i]=1,j=next[j];

    }

}



int main()

{

    while(cin>>n>>m>>K)

    {

        clr(f,0); clr(g,0); clr(visit,0);

        int i,j;

        FOR1(i,n)

        {

            RD(a[i]);

            FOR1(j,K) f[i][j]=f[i-1][j];

            f[i][a[i]]++;

        }

        FOR1(i,m)

        {

            RD(b[i]);

            FOR1(j,K) g[i][j]=g[i-1][j];

            g[i][b[i]]++;

        }

        getNext();

        kmp();

        int ans=0;

        i=1;

        while(i<=n)

        {

            if(visit[i]) i+=m,ans++;

            else i++;

        }

        PR(ans);

    }

}

  

 

你可能感兴趣的:(show)