【POJ 3167】Cow Patterns (KMP+树状数组)
Cow PatternsDescription
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 1In 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 9then 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 1Sample Output
1 3Hint
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 }
2016-08-07 14:38:40