您的位置:首页 > 其它

POJ 3167 Cow Patterns

2016-02-17 22:17 375 查看

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/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: