【POJ 3167】Cow Patterns (KMP+树状数组)

Cow Patterns

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.

【题意】

  

  给定一个模式串,如果在主串中存在这样一个子串:子串长度与模式串长度相同,且子串中各个数字的大、小、同关系和模式串中的大、小、同关系是一样的,就称该子串满足条件。

  比如说模式串:1,4,4,2,3,1 而主串:5,6,2,10,10,7,3,2,9

  那么主串第三位开始的2,10,10,7,3,2就是满足条件的。(即两个子串离散值相等则为相等)

【分析】

  如果单纯判断字母串相等,这题可以用普通的KMP做,但是这里重新定义了相等,我们就要在原的KMP中修改一下。

  两个子串相等,当且仅当其离散值相等。

  

  如图,假设我们已经判断粉框内子串完全相等,我们现在判断各新加一个元素后是否相等:

  只要判断->A串中小于新元素的数字个数 等于 B串中小于新元素的数字个数

  且 A串中等于新元素的数字个数 等于 B串中等于新元素的数字个数 即可。(想一下 离散值 相等 就知道了)

  所以,只要在较快时间内求出区间小于数k的元素个数即可。

  对于A串,我们可以发现粉框的左端是不断向右移的,所以可以用权值树状数组动态维护。

  那个...粉框左端不断向右移,今天才发现~~KMP没学透吧...

代码如下:

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 using namespace std;
  7 #define Maxn 100010
  8 #define Maxk 25010
  9
 10 int n,k,s;
 11 int a[Maxn],b[Maxk],rk[Maxk],sm[Maxk];
 12 int c[30];
 13 int nt[Maxk],td[Maxn];
 14
 15 struct node
 16 {
 17     int x,id;
 18 }t[Maxk];
 19
 20 bool cmp(node x,node y) {return x.x<y.x;}
 21
 22 void add(int x,int y)
 23 {
 24     for(int i=x;i<=30;i+=i&(-i))
 25      c[i]+=y;
 26 }
 27
 28 int gsum(int x)
 29 {
 30     int ans=0;
 31     for(int i=x;i>=1;i-=i&(-i))
 32     {
 33         ans+=c[i];
 34     }
 35     return ans;
 36 }
 37
 38 void init()
 39 {
 40     scanf("%d%d%d",&n,&k,&s);
 41     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
 42     for(int i=1;i<=k;i++) {scanf("%d",&t[i].x);t[i].id=i;}
 43     sort(t+1,t+1+k,cmp);
 44
 45     int p=1;b[t[1].id]=1;
 46     for(int i=2;i<=k;i++)
 47     {
 48         if(t[i].x!=t[i-1].x) p++;
 49         b[t[i].id]=p;
 50     }
 51
 52     memset(c,0,sizeof(c));
 53     for(int i=1;i<=k;i++)
 54     {
 55         rk[i]=gsum(b[i]-1);//less than b[i]
 56         sm[i]=gsum(b[i]);//less or the same as b[i]
 57         add(b[i],1);
 58     }
 59     memset(c,0,sizeof(c));
 60 }
 61
 62
 63
 64 void kmp()
 65 {
 66     nt[1]=0;
 67     int p=0;
 68     for(int i=2;i<=k;i++)
 69     {
 70         while((gsum(b[i]-1)!=rk[p+1]||gsum(b[i])!=sm[p+1])&&p)
 71         {
 72             for(int j=i-p;j<=i-nt[p]-1;j++) add(b[j],-1);
 73             p=nt[p];
 74         }
 75         if(gsum(b[i]-1)==rk[p+1]&&gsum(b[i])==sm[p+1]) p++;
 76         nt[i]=p;
 77         add(b[i],1);
 78     }
 79
 80     memset(c,0,sizeof(c));
 81     p=0;
 82     for(int i=1;i<=n;i++)
 83     {
 84         while(((gsum(a[i]-1)!=rk[p+1]||gsum(a[i])!=sm[p+1])&&p)||p==k)
 85         {
 86             for(int j=i-p;j<=i-nt[p]-1;j++) add(a[j],-1);
 87             p=nt[p];
 88         }
 89         if(gsum(a[i]-1)==rk[p+1]&&gsum(a[i])==sm[p+1]) p++;
 90         td[i]=p;
 91         add(a[i],1);
 92     }
 93 }
 94
 95 int pri[Maxn];
 96 void ffind()
 97 {
 98     int ans=0;
 99     for(int i=1;i<=n;i++) if(td[i]==k)
100     {
101          pri[++ans]=i-k+1;
102     }
103     printf("%d\n",ans);
104     for(int i=1;i<=ans;i++) printf("%d\n",pri[i]);
105 }
106
107 int main()
108 {
109     init();
110     kmp();
111     ffind();
112     return 0;
113 }

[POJ3167]

2016-08-07 14:38:40

时间: 2024-10-07 05:31:53

【POJ 3167】Cow Patterns (KMP+树状数组)的相关文章

poj 3321:Apple Tree(树状数组,提高题)

Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 18623   Accepted: 5629 Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been

POJ 2828 poj 2828 Buy Tickets 【树状数组,已知前n项和为K,返回n值】

题目链接:http://poj.org/problem?id=2828 在一个队列中,一个人想要插队,告诉你每个新来的人会插在i个人后面,求出最后的队列. 如果我们用模拟的话,那么时间复杂度肯定是超了:想想,如果我们逆序,那么最后来的人的位置一定是固定的,这样的话,我们将问题转化成逆序扫描给出数据,插在i个人后面这个数据就变成了在这个人前面需要留出多少个空位.如此我们只需要用树状数组记录前n项总共有多少个空位,每扫描一个数据,就找出能使得他前面正好有i个空位. 这题用树状数组或者线段树都可以,今

POJ 2464 Brownie Points II 树状数组+扫描线

题意奇葩的一笔,本质上就是一个复杂统计,智商低下的我想不出来只好去搜了题解 #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <set> #include <vector> #include <string> #include <queue> #include <deque> #inclu

【bzoj2384】[Ceoi2011]Match 特殊匹配条件的KMP+树状数组

题目描述 给出两个长度分别为n.m的序列A.B,求出B的所有长度为n的连续子序列(子串),满足:序列中第i小的数在序列的Ai位置. 输入 第一行包含两个整数n, m (2≤n≤m≤1000000). 第二行包含n个整数si,构成1,2,…,n的排列,1≤si≤n且si≠sj. 第三行包含m个整数hi,表示建筑的高度(1≤hi≤109,1≤i≤m),所有的hi均不相同. 每一行的整数之间用单个空格隔开. 输出 第一行包含1个整数k ,表示匹配的序列数目.第二行包含k个整数,分别为在正确匹配的每个序

POJ 2299 Ultra-QuickSort (离散化+树状数组)

题目链接:POJ 2299 Ultra-QuickSort 求一串序列相邻连个元素交换多少后,是一串上升的序列. 思路:求该串序列的逆序数,数据比较大,要离散化. AC代码: #include<stdio.h> #include<string.h> #include<set> #include<map> #include<algorithm> #define ll __int64 using namespace std; const ll max

【POJ 1195】 Mobile phones (树状数组)

[POJ 1195] Mobile phones (树状数组) Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 16761   Accepted: 7713 Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The ar

POJ 2155 Matrix(二维树状数组,绝对具体)

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 20599   Accepted: 7673 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

POJ 3378 Crazy Thairs(树状数组+DP)

[题目链接] http://poj.org/problem?id=3378 [题目大意] 给出一个序列,求序列中长度等于5的LIS数量. [题解] 我们发现对于每个数长度为k的LIS有dp[k][i][a[i]]=dp[k-1][i-1][0~a[i]-1] 我们用5个树状数组维护不同长度的LIS,递推即可,注意答案超过LL,需要用大数. [代码] #include <cstdio> #include <algorithm> #include <cstring> usi

POJ 2352 &amp;&amp; HDU 1541 Stars (树状数组)

一开始想,总感觉是DP,可是最后什么都没想到.还暴力的交了一发. 然后开始写线段树,结果超时.感觉自己线段树的写法有问题.改天再写.先把树状数组的写法贴出来吧. ~~~~~~~~~~~~~~~~~~~~~~~~ 树状数组不懂的去看刘汝佳的大白书,那个图画得很清楚. 题目大意:星星的坐标以y递增的顺序给出,这些点的左下方的点数代表这个点的级数,问0~N-1的级数有多少个?其实y根本木有用. 题目链接:http://poj.org/problem?id=2352 http://acm.hdu.edu