思路:
从a串第一个元素i开始作为起点,他的下一个节点位置为i+=p,由此到结尾进行一遍kmp。
然后在从a串的第二个元素开始作为起点,他的下一个节点位置为i+=p,由此到结尾进行一遍kmp。
直到以p位置为起点,进行一遍kmp。至此将a串遍历了一遍,结果也就出来了。
AC代码:
#include <iostream>
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <string.h>
using namespace std;
int a[1000010];
int b[1000010];
int nex[1000010];
int n,m;
void getnext(){
int k = 0;
for(int i = 1;i < m;i++){
while(b[i] != b[k] && k != 0){
k = nex[k-1];
}
if(b[i] == b[k]){
k++;
}
nex[i] = k;
}
}
int ans = 0;
int p;
void kmp(int d){
int k = 0;
for(int i = d;i < n;i+=p){
while(a[i] != b[k] && k != 0){
k = nex[k-1];
}
if(a[i] == b[k]){
k++;
if(k == m){
ans++;
k = nex[k-1];
}
}
}
}
int main(){
int t;
cin>>t;
int cas = 0;
while(t--){
ans=0;
cas++;
scanf("%d%d%d",&n,&m,&p);
for(int i = 0;i < n;i++){
scanf("%d",a+i);
}
for(int i = 0;i < m;i++){
scanf("%d",b+i);
}
getnext();
if(1+(n-1)/p >= m){
for(int i = 0;i < p;i++){
kmp(i);
}
}
printf("Case #%d: %d\n",cas,ans);
}
return 0;}