POJ 3167 Cow Patterns

Cow Patterns

Time Limit: 2000MSMemory Limit: 65536K
Total Submissions: 4149Accepted: 1484

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.

这个题是第一次遇到的匹配波动趋势的题目,刚接触有点难,然后看了bin神的题解后终于明白该怎么弄
当然网上也有树状数组或者是线段树+kmp来解决这个问题的,其实原理差不多,用kmp即可。
题意是给定一串数字作为主串,另外一串数字作为匹配串,求解符合匹配串的数字的趋势的主串中的串的个数和起始位置。所谓匹配趋势意思是对应位置数字相等的地方,另外一个串数字可以不同,但是大小仍要相同,同理大和小的比较。具体看Test Case
对于这个题意,我们需要从确定对应位置数字入手,一个数字在一个串里扮演的地位和位置是由它与前面的数字的大小决定的,统计某个位置的数字之前比该数字数值小和相等的数量,就可以确定这个数字的位置。弄清楚了这一点,进行kmp就不是以字符匹配作为根据来建立next数组了,而是根据比该数值小和相等的数的数量来进行next数组的计算和kmp的匹配。
按照题目中的Test Casa 举例匹配串。
pos :    0 1 2 3 4 5
value : 1 4 4 2 3 1
首先,第pos = 0和pos = 1对应的next一定是-1, 0没有问题。
当pos = 1时,pos = 0 和 pos = 1两个数进行匹配,发现两者对应的区间pos(0,0)和pos(0,1)比该数字小的数字数量都相同,而与对应位置数字相同的数字个数也相同都是1,所以next[2] = 1
对于第pos = 2时的数4,根据计算next数组的法则,我们需要进行pos = 1和pos = 2两个数的匹配,发现pos(0,2)和(0,1)区间对应的比pos = 2和pos = 1时的数值小的数字的数量都是0,但是,pos = 1时与该数相等的数数量比pos = 2时小1,所以不匹配,j = next[j],继续比较pos =2 和pos = 0,此时j = -1,直接i ++, j ++,next[3] = 0
同理后面的next数组和kmp匹配过程
具体代码如下:需要注意kmp时候时的边界问题,因此wa好多次
/*************************************************************************
	> File Name: Cow_Patterns.cpp
	> Author: Zhanghaoran
	> Mail: chilumanxi@xiyoulinux.org
	> Created Time: 2016年01月20日 星期三 17时49分13秒
 ************************************************************************/

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <vector>
using namespace std;

int N, K, S;
int sp[100010];
int pa[25010];
int as[100010][32];
int bs[25010][32];
vector<int>ans;
int next[25010];

void kmp_pre(){
    int i = 0;
    int j = next[0] = -1;
    int t11, t12, t21, t22;
    while(i < K){
        t11 = t12 = t21 = t22 = 0;
        for(int k = 1; k < pa[i]; k ++){
            if(i > j)    
                t11 += bs[i][k] - bs[i - j - 1][k];
            else
                t11 += bs[i][k];
        }
        t12 = bs[i][pa[i]] - bs[i - j - 1][pa[i]];
        
        for(int k = 1; k < pa[j]; k ++){
            t21 += bs[j][k];
        }

        t22 = bs[j][pa[j]];

        if(j == -1 || (t11 == t21 && t12 == t22)){
            next[++ i] = ++ j;
        }
        else
            j = next[j];
    }

}


void kmp(){
    kmp_pre();
    int i= 0, j = 0;
    int t11, t12 , t21, t22;
    while(i < N){
        t11 = t12 = t21 = t22 = 0;
        for(int k = 1; k < sp[i]; k ++){
            if(i > j)
                t11 += as[i][k] - as[i - j - 1][k];
            else
                t11 += as[i][k];
        }
        if(i > j)
            t12 = as[i][sp[i]] - as[i - j - 1][sp[i]];
	    else
            t12 = as[i][sp[i]];
        for(int k = 1; k < pa[j]; k ++){
            t21 += bs[j][k];
        }
        t22 = bs[j][pa[j]];

        if(j == -1 || (t11 == t21 && t12 == t22)){
            i ++;
            j ++;
            if(j >= K){ 
                ans.push_back(i - K + 1);
                j = next[j];
            }
        }
        else
            j = next[j];
    }
}

int main(void){
    cin >> N >> K >> S;
    for(int i = 0 ;i < N; i ++){
        scanf("%d", &sp[i]);
        if(i == 0){
            for(int j = 0; j < 30; j ++){
                as[i][j] = 0;
            }
        }
        else{
            for(int j = 0; j < 30; j ++)
                as[i][j] = as[i - 1][j];
        }
        as[i][sp[i]] ++;

    }
    for(int i = 0; i < K; i ++){
        scanf("%d", &pa[i]);
        if(i == 0){
            for(int j = 0; j < 30; j ++){
                bs[i][j] = 0;
            }
        }
        else{
            for(int j = 0; j < 30; j ++)
                bs[i][j] = bs[i - 1][j];
        }
        bs[i][pa[i]] ++;
    }
    ans.clear();
    kmp();
    cout << ans.size() << endl;
    for(int i = 0; i < ans.size(); i ++)
        printf("%d\n", ans[i]);

}

 

查看原文:http://chilumanxi.org/2016/02/17/poj-3167-cow-patterns/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值