HDU4749 Parade Show(KMP)

时间:2022-06-07 06:11:44

题目链接: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);
    }
}