【Foreign】字符串匹配 [KMP]
字符串匹配
Time Limit: 10 Sec Memory Limit: 256 MBDescription
Input
Output
Sample Input
3 3
6 3
1 2 1 2 3 2
3 1 3
6 3
1 2 1 2 1 2
3 1 3
6 3
1 1 2 1 2 1
3 1 3
6 3
1 2 1 2 3 2
3 1 3
6 3
1 2 1 2 1 2
3 1 3
6 3
1 1 2 1 2 1
3 1 3
Sample Output
3
1 2 4
4
1 2 3 4
3
2 3 4
1 2 4
4
1 2 3 4
3
2 3 4
HINT
Solution
发现题目中颜色的具体权值是对答案无关的,然后就是只要相对位置一样即可。
那么显然是一个KMP的模型,变相更改,条件改为:两个字符上一次出现的相对位置相同(也就是位置差值相等)。
那么我们只要求出差值来KMP即可,再考虑一下串长对于答案的影响,差值>串长显然是不会影响答案的,但是直接匹配的话可能将这种情况默认为不可行,所以我们在匹配的时候判断一下串长,若dist>=当前匹配串长则同设为0即可,更新fail的时候也要这么做。这样做KMP即可求出答案。
Code
1 #include<iostream>
2 #include<string>
3 #include<algorithm>
4 #include<cstdio>
5 #include<cstring>
6 #include<cstdlib>
7 #include<ctime>
8 #include<cmath>
9 using namespace std;
10
11 const int ONE=10001;
12
13 int T,C;
14 int n,m;
15 int a[ONE],b[ONE];
16 int da[ONE],db[ONE],la[ONE],lb[ONE];
17 int fail[ONE],j;
18 int Ans[ONE],ans_num;
19
20 int get()
21 {
22 int res=1,Q=1;char c;
23 while( (c=getchar())<48 || c>57 )
24 if(c=='-')Q=-1;
25 res=c-48;
26 while( (c=getchar())>=48 && c<=57 )
27 res=res*10+c-48;
28 return res*Q;
29 }
30
31 int Da(int i,int len) {if(da[i]>=len) return 0;return da[i];}
32 int Db(int i,int len) {if(db[i]>=len) return 0;return db[i];}
33
34 int main()
35 {
36 T=get(); C=get();
37 while(T--)
38 {
39 n=get(); m=get();
40 memset(la,0,sizeof(la)); memset(lb,0,sizeof(lb));
41 for(int i=1;i<=n;i++) a[i]=get();
42 for(int i=1;i<=m;i++) b[i]=get();
43
44 for(int i=1;i<=n;i++) da[i]=i-la[a[i]], la[a[i]]=i;
45 for(int i=1;i<=m;i++) db[i]=i-lb[b[i]], lb[b[i]]=i;
46
47 j=0;
48 for(int i=2;i<=m;i++)
49 {
50 j=fail[i-1];
51 while(j && Db(j+1,j+1)!=Db(i,j+1)) j=fail[j];
52 if(Db(j+1,j+1) == Db(i,j+1)) j++; else j=0;
53 fail[i] = j;
54 }
55
56 j=0; ans_num=0;
57 for(int i=1;i<=n;i++)
58 {
59 while(j && Db(j+1,j+1)!=Da(i,j+1)) j=fail[j];
60 if(Db(j+1,j+1) == Da(i,j+1)) j++; else j=0;
61 if(j==m) Ans[++ans_num] = i-m+1, j=fail[j];
62
63 }
64
65 printf("%d\n",ans_num);
66 for(int i=1;i<=ans_num;i++)
67 printf("%d ",Ans[i]);
68 printf("\n");
69 }
70 }