思路:乍一看就是扩展KMP,但这题还是要一点点转化。
如果想要满足题目要求,匹配段肯定间隔是相反的。
比如样例中在0位置匹配:
1 (+3)4(+2) 6 9
5 (-3)2 (-2) 0
Code:
#include <bits/stdc++.h>
using namespace std;
const int AX = 1e5+66;
int n , m;
int a[AX];
int b[AX];
int sa[AX];
int sb[AX];
int next1[AX];
int extend[AX];
int res ;
int re[AX];
void getNext(){
int i = 0, po = 0;
int len = m - 1;
next1[0] = len;
while( i + 1 < len && sb[i] == sb[i+1] ) i++;
next1[1] = i;
po = 1;
for( int i = 2 ; i < len ; i++ ){
if( po + next1[po] > i + next1[i-po] ){
next1[i] = next1[i-po];
}else{
int j = next1[po] + po - i;
if( j < 0 ) j = 0 ;
while( i + j < len && sb[i+j] == sb[j] ) j++;
next1[i] = j ;
po = i;
}
}
}
void getExtend(){
int i = 0 , po;
int len = n - 1;
int lenm = m - 1;
getNext();
while( i < len && i < lenm && sa[i] == sb[i] ) i++;
extend[0] = i;
po = 0;
if( extend[0] == lenm ) {
re[res++] = 0;
}
for( int i = 1 ; i < len ; i++ ){
if( po + extend[po] > i + next1[i-po] ){
extend[i] = next1[i-po];
}else{
int j = extend[po] + po - i;
if( j < 0 ) j = 0;
while( i + j < len && j < lenm && sa[i+j] == sb[j] ) j++;
extend[i] = j;
po = i;
}
if( extend[i] == lenm ){
re[res++] = i;
}
}
}
int main(){
res = 0;
scanf("%d%d",&n,&m);
for( int i = 0 ; i < n ; i++ ){
scanf("%d",&a[i]);
if( i ) sa[i-1] = 0-(a[i] - a[i-1]);
}
for( int i = 0 ; i < m ; i++ ){
scanf("%d",&b[i]);
if( i ) sb[i-1] = b[i] - b[i-1];
}
getExtend();
printf("%d\n",res);
for( int i = 0 ; i < res ;i ++ ){
printf("%d ",re[i]);
}printf("\n");
return 0 ;
}