POJ 3167 Cow Patterns(KMP)

Description

A particular subgroup of K (1 <= K <= 25,000) of Farmer John's cows likes to make trouble. When placed in a line, these troublemakers stand together in a particular order. In order to locate these troublemakers, FJ has lined up his N (1 <= N <= 100,000) cows. The cows will file past FJ into the barn, staying in order. FJ needs your help to locate suspicious blocks of K cows within this line that might potentially be the troublemaking cows.

FJ distinguishes his cows by the number of spots 1..S on each cow's coat (1 <= S <= 25). While not a perfect method, it serves his purposes. FJ does not remember the exact number of spots on each cow in the subgroup of troublemakers. He can, however, remember which cows in the group have the same number of spots, and which of any pair of cows has more spots (if the spot counts differ). He describes such a pattern with a sequence of K ranks in the range 1..S. For example, consider this sequence:

      1 4 4 3 2 1
In this example, FJ is seeking a consecutive sequence of 6 cows from among his N cows in a line. Cows #1 and #6 in this sequence have the same number of spots (although this number is not necessarily 1) and they have the smallest number of spots of cows #1..#6 (since they are labeled as '1'). Cow #5 has the second-smallest number of spots, different from all the other cows #1..#6. Cows #2 and #3 have the same number of spots, and this number is the largest of all cows #1..#6.

If the true count of spots for some sequence of cows is:

 5 6 2 10 10 7 3 2 9
then only the subsequence 2 10 10 7 3 2 matches FJ's pattern above.

Please help FJ locate all the length-K subsequences in his line of cows that match his specified pattern.

Input

Line 1: Three space-separated integers: N, K, and S

Lines 2..N+1: Line i+1 describes the number of spots on cow i.

Lines N+2..N+K+1: Line i+N+1 describes pattern-rank slot i.

Output

Line 1: The number of indices, B, at which the pattern matches

Lines 2..B+1: An index (in the range 1..N) of the starting location where the pattern matches.

Sample Input

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

Sample Output

1
3

Hint

Explanation of the sample:

The sample input corresponds to the example given in the problem statement.

There is only one match, at position 3 within FJ's sequence of N cows.
本题的思路是kmp算法进行匹配。分别用as,bs数组记录0~n期间每个数出现了几次。(方便后续计算相对大小)
然后求next数组时根据该数前面有几个比她小的以及和她相同的来确定在串中的位置是否匹配。
即判断是否在串中相对大小匹配只用判断该数前面的他小的数的数量是否相同以及与他相等的数的数量是否相同即可。
注释里应该挺清楚的了
AC代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#define MAXN1 100005
#define MAXN2 25005
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int n,k,s,a[MAXN1],b[MAXN2],knext[MAXN2];//a为主串,b为模式串 
int as[MAXN1][30],bs[MAXN2][30];//as[i][j]=k.表示对于a的前i+1个数中,j出现了k次。(bs同理
vector<int>ans;//答案记录数组 
void Init(){//初始化as,bs令其满足条件 
    for(int i=0;i<n;i++){
        if(i==0)
            for(int j=1;j<=s;j++)
                as[i][j]=0;
        else
            for(int j=1;j<=s;j++)
                as[i][j]=as[i-1][j];
        as[i][a[i]]++;
    } 
    for(int i=0;i<k;i++){
        for(int j=1;j<=s;j++)
            if(i==0)
                bs[i][j]=0;
            else
                bs[i][j]=bs[i-1][j];
        bs[i][b[i]]++;
    }
}
void Find_next(){//即先与自己匹配一次 
    int i,j; 
    knext[0]=i=-1;//i为模式串的模式串 
    j=0;//j为模式串的主串 
    while(j<k){
        if(i==-1){
            knext[++j]=++i;
            continue;
        }
        int a1=0,a2=0,b1=0,b2=0;//a1为主串中第几大,a2为主串中相同的数的个数,b1为模式串中……,b2为模式中……
        for(int m=1;m<b[j];m++)//判断小于该值的点在前面出现了几个(即该值是第几+1大。 
            if(j-i>0)//即已经失配过了.需要减去前面不匹配的 
                a1+=bs[j][m]-bs[j-i-1][m];
            else
                a1+=bs[j][m];
        if(j-i>0)//判断等于该值的点在前面出现了几个 
            a2=bs[j][b[j]]-bs[j-i-1][b[j]];
        else
            a2=bs[j][b[j]];
        for(int m=1;m<b[i];m++)
            b1+=bs[i][m];
        b2=bs[i][b[i]]; 
        if(a1==b1&&a2==b2)
            knext[++j]=++i;
        else
            i=knext[i];
    }
}
void Kmp(){
    ans.clear();
    int i=0,j=0;
    while(j<n){
        int a1=0,a2=0,b1=0,b2=0;
        for(int m=1;m<a[j];m++)//主串的处理 
            if(j-i>0)
                a1+=as[j][m]-as[j-i-1][m];
            else
                a1+=as[j][m];
        if(j-i>0)
            a2=as[j][a[j]]-as[j-i-1][a[j]];
        else 
            a2=as[j][a[j]];
        for(int m=1;m<b[i];m++)//模式串的处理 
            b1+=bs[i][m];
        b2=bs[i][b[i]];
        if(i==-1||a1==b1&&a2==b2){
            i++,j++;
            if(i>=k){
                ans.push_back(j-k+1);
                i=knext[i];
            }
        }else
            i=knext[i];
    }
}
int main(){
    scanf("%d%d%d",&n,&k,&s);//s为几种(1~s),s为(1~25)
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    for(int i=0;i<k;i++)
        scanf("%d",&b[i]); 
    Init();
    Find_next();
    Kmp();
    printf("%d\n",ans.size());
    for(int i=0;i<ans.size();i++)
        printf("%d\n",ans[i]); 
}

 

 
posted @ 2021-03-10 20:02  mikku  阅读(212)  评论(0)    收藏  举报